std::vector<> considered harmful

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

flok

std::vector<> considered harmful

Post by flok »

Hi,

I always thought that std::vector<> would have some overhead but probably not beyond the noise-factor. While profiling my chess program using valgrind I saw that my "addMove" method used quite a bit of cpu-time. So I did some googling and found reports on stackoverflow that in some cases std::vector<> indeed is a bit slow.

In my program I used that vector for storing lists of moves. At allocation time I made sure that the vector was pre-allocating memory.

I replaced this yesterday with a custom MoveList class (with a static allocation of 218 moves) and lo and behold the most conservative speed-up of my chess program was 16%! That is amazing!

The code is as follows. I wonder if any of you has suggestions for improving it any further.

Oh the 218 moves: I googled that 218 is the maximum number of moves that can happen in a position.

Code: Select all

class MoveList
&#123;
private&#58;
        Move moves&#91;218&#93;;
        int nIn;

public&#58;
        inline MoveList&#40;)
        &#123;
                nIn = 0;
        &#125;

        inline void clear&#40;)
        &#123;
                nIn = 0;
        &#125;

        inline void push_back&#40;const Move & m&#41;
        &#123;
                moves&#91;nIn++&#93; = m;
        &#125;

        inline const Move & at&#40;const long unsigned int idx&#41; const
        &#123;
                return moves&#91;idx&#93;;
        &#125;

        inline void set&#40;const long unsigned int idx, const Move & m&#41;
        &#123;
                moves&#91;idx&#93; = m;
        &#125;

        inline size_t size&#40;) const
        &#123;
                return nIn;
        &#125;

        inline bool empty&#40;) const
        &#123;
                return nIn == 0;
        &#125;

        inline void erase&#40;const long unsigned int idx&#41;
        &#123;
                long unsigned int n_to_move = &#40;nIn - idx&#41; - 1;
                if &#40;n_to_move > 0&#41;
                        memmove&#40;&moves&#91;idx&#93;, &moves&#91;idx + 1&#93;, n_to_move * sizeof&#40;Move&#41;);

                nIn--;
        &#125;

        void sort&#40;int (*compare_func&#41;&#40;const void *m1, const void *m2, void *arg&#41;, void *arg&#41;;
&#125;;


void MoveList&#58;&#58;sort&#40;int (*compare_func&#41;&#40;const void *m1, const void *m2, void *arg&#41;, void *arg&#41;
&#123;
        if &#40;nIn&#41;
                qsort_r&#40;moves, nIn, sizeof&#40;Move&#41;, compare_func, arg&#41;;
&#125;
kinderchocolate
Posts: 454
Joined: Mon Nov 01, 2010 6:55 am
Full name: Ted Wong

Re: std::vector<> considered harmful

Post by kinderchocolate »

Well, each operation to std::vector involves a copy operation. It's only efficient if T is a primary type. I also did a simple static allocation of arrays of moves. Simple and much faster.
BeyondCritics
Posts: 396
Joined: Sat May 05, 2012 2:48 pm
Full name: Oliver Roese

Re: std::vector<> considered harmful

Post by BeyondCritics »

Hi Folkert,

thank you for sharing, but frankly i don't got the point. Could you point out the difference, why do you think std:vector is slow in this case?
Thank you
jdart
Posts: 4366
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: std::vector<> considered harmful

Post by jdart »

stl::vector does dynamic memory allocation. So replacing it with a fixed allocation on the stack will be faster.

I use my own <vector> replacement (https://github.com/jdart1/arasan-chess/ ... /arasvec.h) largely for historical reasons, but it's not used in time-critical code: it stores the global list of moves made in the game, for example. I use straight arrays in the search.

--Jon
flok

Re: std::vector<> considered harmful

Post by flok »

jdart wrote:stl::vector does dynamic memory allocation. So replacing it with a fixed allocation on the stack will be faster.
Well that is true normally but after instantiating the vector object, I used to call reserve() on it so that it did not need to constanly call realloc on it.
User avatar
Bloodbane
Posts: 154
Joined: Thu Oct 03, 2013 4:17 pm

Re: std::vector<> considered harmful

Post by Bloodbane »

Did you do something like this:

std::vector<Move> moveList(128);

or something like this:

std::vector<Move> moveList;
moveList.reserve(128);

There can be a big difference between them, depending on if Move(or whatever the vector consists of) is initialized or not. Still, that's probably going to be slower than the custom MoveList.

EDIT: and the answer comes two minutes before I post my message, brilliant.
Last edited by Bloodbane on Thu Sep 25, 2014 4:48 pm, edited 1 time in total.
Functional programming combines the flexibility and power of abstract mathematics with the intuitive clarity of abstract mathematics.
https://github.com/mAarnos
flok

Re: std::vector<> considered harmful

Post by flok »

BeyondCritics wrote:thank you for sharing, but frankly i don't got the point. Could you point out the difference, why do you think std:vector is slow in this case?
Thank you
I'm not sure. Maybe because it calls the constructor of each element that it adds (but I'm adding structs so not likely to be that problem) or maybe the reserve() is a no-op and it is doing a realloc with one more element, frankly I don't know.

http://stackoverflow.com/questions/3664 ... ain-arrays
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: std::vector<> considered harmful

Post by AlvaroBegue »

There is no mystery here. std::vector will always use dynamic memory allocation. If you use `reserve' at the beginning you won't need any reallocations, but you still need the one dynamic memory allocation. Besides the cost of allocating and freeing memory, you may also end up with worse cache coherence than if your move list lived on the stack.

The only place where I use std::vector in my engine is in the transpositions table. I certainly don't do any dynamic memory allocation in the search functions, because it is expensive and because it is not needed.
BeyondCritics
Posts: 396
Joined: Sat May 05, 2012 2:48 pm
Full name: Oliver Roese

Re: std::vector<> considered harmful

Post by BeyondCritics »

To be sure you could use e.g. Zoom (http://www.rotateright.com/) or Callgrind and then compare the differences on differenct sources.
Many would be interested...
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: std::vector<> considered harmful

Post by Henk »

In C# is use List<> for the move list. Should be equivalent to a generic array. To add a move to the list I use List<MoveBase>:Add(move)