Help improving this code ?!

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

pkumar
Posts: 100
Joined: Tue Oct 15, 2013 5:45 pm

Re: Help improving this code ?!

Post by pkumar »

AlvaroBegue wrote: Personal opinion: If you want to live a happy life, don't use virtual inheritance, multiple inheritance or non-public inheritance. Use simple, non-virtual, public inheritance, and only to get polymorphic behavior, and only when inheritance expresses an "IS-A" relationship.
I am happy to see this topic. I am in the middle of changing my essentially C source code to a truely object oriented one. I have used simple inheritance but flouted the IS-A rule to save some typing effort for now. The offending classes look as below.

class A
{ calculate lv's };

class B : public A
{ code };

class C : public B
{ code };

The engine now works with ~25% drop in nps at early mid-game. Web search did not yield a definite answer to whether inheritance or OOP per se can cause this much drop. I intend to go ahead with changes and reduce one level of inheritance by using composition thus:

class A
{ calculate lv's };

const A lv; //access lv members as needed

Can this improve nps?
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: Help improving this code ?!

Post by AlvaroBegue »

pkumar wrote:
AlvaroBegue wrote: Personal opinion: If you want to live a happy life, don't use virtual inheritance, multiple inheritance or non-public inheritance. Use simple, non-virtual, public inheritance, and only to get polymorphic behavior, and only when inheritance expresses an "IS-A" relationship.
I am happy to see this topic. I am in the middle of changing my essentially C source code to a truely object oriented one. I have used simple inheritance but flouted the IS-A rule to save some typing effort for now. The offending classes look as below.

class A
{ calculate lv's };

class B : public A
{ code };

class C : public B
{ code };

The engine now works with ~25% drop in nps at early mid-game. Web search did not yield a definite answer to whether inheritance or OOP per se can cause this much drop. I intend to go ahead with changes and reduce one level of inheritance by using composition thus:

class A
{ calculate lv's };

const A lv; //access lv members as needed

Can this improve nps?

You shouldn't see any drop in speed whatsoever. If you are new to C++, you might have accidentally used some expensive feature that you shouldn't be using, like dynamic memory allocation, unnecessary copies, unnecessary construction/destruction of objects that could have longer lifespans, function calls that are hard to inline, cache-unfriendly memory layouts... But if you understand what your code is doing and avoid those things, there is zero overhead above C.
pkumar
Posts: 100
Joined: Tue Oct 15, 2013 5:45 pm

Re: Help improving this code ?!

Post by pkumar »

AlvaroBegue wrote: You shouldn't see any drop in speed whatsoever. If you are new to C++, you might have accidentally used some expensive feature that you shouldn't be using, like dynamic memory allocation, unnecessary copies, unnecessary construction/destruction of objects that could have longer lifespans, function calls that are hard to inline, cache-unfriendly memory layouts... But if you understand what your code is doing and avoid those things, there is zero overhead above C.
Your reply makes me hopeful about speed. I am indeed not a professional programmer. But I think I am not doing "unnecessary copies, unnecessary construction/destruction of objects that could have longer lifespans" . My code is simple. Objects are long term and members are accessed as needed. Objects are passed to methods rarely and by reference. I shall look for "function calls that are hard to inline, cache-unfriendly memory layouts...". Thanks for pointing out.
Fulvio
Posts: 395
Joined: Fri Aug 12, 2016 8:43 pm

Re: Help improving this code ?!

Post by Fulvio »

pkumar wrote:
AlvaroBegue wrote:I shall look for "function calls that are hard to inline, cache-unfriendly memory layouts...". Thanks for pointing out.
The order of the member variables is also important:
http://en.cppreference.com/w/cpp/langua ... #Alignment

Code: Select all

struct S{
  char a;
  char b;
  int c;
};
have a size of 8 bytes.

The same members with different order:

Code: Select all

struct S{
  char a;
  int c;
  char b;
};
have a size of 12 bytes.
Wasted bytes may generate more cache misses (and slower code).
Henk
Posts: 7218
Joined: Mon May 27, 2013 10:31 am

Re: Help improving this code ?!

Post by Henk »

Sven Schüle wrote:
Henk wrote:They always told me that object oriented programming is not for free. Calling a virtual method is like dereferencing a pointer to a function. So if you want to code more efficiently use C instead of C++. No nonsense with virtual tables.
Henk, please ... how can we prevent you from writing nonsense in a serious thread where someone is looking for help?
I did not know that his engine has an elo of 7000 and that he is busy with last step of optimization before project is closed.

I guess other developers might be busy with solving ugly bugs or improving move ordering, reductions and pruning. For them readable, flexible code is most important.

Don't worry I keep away from this discussion.
pkumar
Posts: 100
Joined: Tue Oct 15, 2013 5:45 pm

Re: Help improving this code ?!

Post by pkumar »

Fulvio wrote:The order of the member variables is also important:
http://en.cppreference.com/w/cpp/langua ... #Alignment
Thanks for the link. I normally check a class/structure for expected size. May have missed some in a hurry to get a working program first. A lot of work remains.
mar
Posts: 2555
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Help improving this code ?!

Post by mar »

AlvaroBegue wrote:You generally don't need a pointer to the parent, unless you are using virtual inheritance.
Agreed, I never used virtual inheritance.

I only used multiple inheritance a couple of times (in 99.99% I use either single inheritance or composition), where one of the base classes was non-virtual.

The problem with multiple inheritance of virtual classes (=classes with virtual methods) is that you get multiple vtbl ptrs packed into derived class so that the code can offset the pointer when casting to base type.

As for virtual calls: depends of whether they are in cache or not. And they are still nothing compared to dynamic dispatch in ObjectiveC :)

For a chess engine, speaking of time-critical parts, I see no reason at all to use virtual methods or inheritance.

I wonder why people still believe in the myth that C is faster than C++ (or the other way around); if the backend optimizer is the same (assuming the same compiler) - unless you do something dumb,
you should get the same performance.

I'm shocked to see that some people try to write chess engines in the "enterprise" way, you don't need tons of over-engineered bs to solve simple problems (I can see a "MoveFactory" etc. :)
Those who don't have the slightest idea how things work under the hood can then expect some unpleasant suprises :)
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: Help improving this code ?!

Post by AlvaroBegue »

mar wrote:I wonder why people still believe in the myth that C is faster than C++ (or the other way around); if the backend optimizer is the same (assuming the same compiler) - unless you do something dumb,
you should get the same performance.
I just want to quickly comment that there are a few things that are not easy to make as fast in C and they are in C++. The most common one is sorting simple objects (say, moves). In C++ I can call std::sort and pass it a comparison functor which the compiler can then inline. In C you use qsort and you pass it a comparison function pointer, which then incurs similar costs to a virtual function call for every invocation.

Perhaps C compilers have gotten smart enough that this is no longer an issue, but it's hard to imagine how that would work.
mar
Posts: 2555
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Help improving this code ?!

Post by mar »

AlvaroBegue wrote:I just want to quickly comment that there are a few things that are not easy to make as fast in C and they are in C++. The most common one is sorting simple objects (say, moves). In C++ I can call std::sort and pass it a comparison functor which the compiler can then inline. In C you use qsort and you pass it a comparison function pointer, which then incurs similar costs to a virtual function call for every invocation.

Perhaps C compilers have gotten smart enough that this is no longer an issue, but it's hard to imagine how that would work.
I even saw C++ code using C qsort.
But for a chess engine it should be trivial to do insertion sort on int array.

The problem I see is that qsort in C is a library function so the compiler doesn't know what's inside and therefore unable to inline it.
(but if IPO is possible then maybe it might be doable, but I'm not sure if it's a good idea - if the program is linking the CRT dynamically,
I can imagine it might cause potential problems - inlining some part using version x and linking the rest against version y)
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Help improving this code ?!

Post by Ras »

AlvaroBegue wrote:In C you use qsort and you pass it a comparison function pointer, which then incurs similar costs to a virtual function call for every invocation.
That's why I have a dedicated shellsort for the move lists.