Code: Select all
For exemple:
eval_white_pawn ()
Eval_black_pawn ()
eval_white_knight ()
eval_black_knight ()
And so on...
Code: Select all
eval_pawn ()
eval_knight ()
Bests
Dany
Moderators: hgm, Rebel, chrisw
Code: Select all
For exemple:
eval_white_pawn ()
Eval_black_pawn ()
eval_white_knight ()
eval_black_knight ()
And so on...
Code: Select all
eval_pawn ()
eval_knight ()
Not sure why it would be good. You might eliminate a few branches by doing that, but you double the cache footprint. My program gained speed when I got rid of all the duplicated code for black and white. I don't have any, now.Daniel Anulliero wrote:I read somewhere (can't remember where exactly) It's better to have in our eval () separate functions for white and blackInstead of :Code: Select all
For exemple: eval_white_pawn () Eval_black_pawn () eval_white_knight () eval_black_knight () And so on...
If it's better can you explain why?Code: Select all
eval_pawn () eval_knight ()
Bests
Dany
iirc , it was marco costalba who recommended (somewhere in the forum) to make like thatbob wrote:Not sure why it would be good. You might eliminate a few branches by doing that, but you double the cache footprint. My program gained speed when I got rid of all the duplicated code for black and white. I don't have any, now.Daniel Anulliero wrote:I read somewhere (can't remember where exactly) It's better to have in our eval () separate functions for white and blackInstead of :Code: Select all
For exemple: eval_white_pawn () Eval_black_pawn () eval_white_knight () eval_black_knight () And so on...
If it's better can you explain why?Code: Select all
eval_pawn () eval_knight ()
Bests
Dany
I think they do some of this via templates. You should test it, but I found one copy was faster than two. More cache friendly + only half as much code to read from memory into cache when you need it and it is not there.Daniel Anulliero wrote:iirc , it was marco costalba who recommended (somewhere in the forum) to make like thatbob wrote:Not sure why it would be good. You might eliminate a few branches by doing that, but you double the cache footprint. My program gained speed when I got rid of all the duplicated code for black and white. I don't have any, now.Daniel Anulliero wrote:I read somewhere (can't remember where exactly) It's better to have in our eval () separate functions for white and blackInstead of :Code: Select all
For exemple: eval_white_pawn () Eval_black_pawn () eval_white_knight () eval_black_knight () And so on...
If it's better can you explain why?Code: Select all
eval_pawn () eval_knight ()
Bests
Dany
Anyway , thanks for the answer !
I think worrying about branches today is pointless. In the evaluation, all the if (stm) branches will be correctly predicted by the correlated part of the branch predictor hardware. It will notice that there are "sets" of branches that all go the same way, and after the first few it will "get 'em all" every time anyway. I agree with you about cache. Doubling code is halving cache.hgm wrote:In my experience efficient cache usage is the all-important factor in optimizing code. So I would never duplicate code just to safe a couple of branches.
Besides, I hardly ever need branches. If you have an stm variable that has value 0 or 1 (say), you can use (2*stm-1) to generate a factor +/-1 with which you can multiply an evaluation that you coded for the white point-of-view, or use it as an extra index to the piece list to acces black or white pieces, or calculate 16*stm-8 to generate a step in the forward direction, etc.
In my experience there's no yes/no answer in general to that question. It's not that clear cut, so don't listen to Bob and HGM's hand waving arguments about cache efficiency and branch-prediction.Daniel Anulliero wrote:I read somewhere (can't remember where exactly) It's better to have in our eval () separate functions for white and blackInstead of :Code: Select all
For exemple: eval_white_pawn () Eval_black_pawn () eval_white_knight () eval_black_knight () And so on...
If it's better can you explain why?Code: Select all
eval_pawn () eval_knight ()
Bests
Dany
I can guarantee you that the if (wtm) type branches will be predicted perfectly after the first 10 are handled. So they are completely irrelevant. All that is left is cache issues. You should avoid topics you don't understand, just because you like to get in a personal dig here and there for unknown reasons.lucasart wrote:In my experience there's no yes/no answer in general to that question. It's not that clear cut, so don't listen to Bob and HGM's hand waving arguments about cache efficiency and branch-prediction.Daniel Anulliero wrote:I read somewhere (can't remember where exactly) It's better to have in our eval () separate functions for white and blackInstead of :Code: Select all
For exemple: eval_white_pawn () Eval_black_pawn () eval_white_knight () eval_black_knight () And so on...
If it's better can you explain why?Code: Select all
eval_pawn () eval_knight ()
Bests
Dany
=> Measure it yourself.
Sometimes the increased cache pressure is overkill, sometimes the saved branches are what matters. It's not obvious just by looking at the code. I've found some of Stockfish's templatizations to be useless and even counter-productive, but many of them are still beneficial.
- In C++ it's pretty trivial to experiment. First write the code with a function parameter, then make that a template argument, and do some speed test of both versions (verify first that they are functionally equal, obviously).
- In C you can do that with some ugly recursive inclusion and macros (see Robbolito).
- But one thing you should NEVER do is duplicate code explicitely. It's a recipie for disaster and unmaintainable code (so easy to modify one without the other and endup with subtle asymmetric bugs).