Question About CPP-C#, Performance, and Square Represenation

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

bpfliegel
Posts: 71
Joined: Fri Mar 16, 2012 10:16 am

Re: Question About CPP-C#, Performance, and Square Represena

Post by bpfliegel »

Cheney wrote:Thanks Fred, I looked at but now need to research just what I am looking at and of course, the 10 day trial now expired. Through this exercise, I learned what the IL Disassembler in the SDK is and will check it out a little more.

Somewhere in looking at DotTrace and ilspy, I launched the exe in the x64\release folder and it performed much better (perft 5 in .5 and perft 6 in 8). I did not know that executing the code while in VS2010 actually affected performance - probably from being attached to the debugger. I feel so duh :)

Anyway, thanks for the help. I am going to continue working on enhancing the search and evaluation and along the way look more at the MSIL code, learn about it, and see if there are ways to increase performance.

Thanks again for all the help :)
Also don't forget to tick that 'Optimize code' checkbox when compiling - as stupid as it looks it will give you 30-40% boost.

Good luck, Balint
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: Question About CPP-C#, Performance, and Square Represena

Post by Rein Halbersma »

emadsen wrote:Rein,

My use of the yield statement is in code that's not ready for release. Here are some code snippets to give you sense of how it works.

I'll show the capture-only enumerator because it's simpler.

Code: Select all

public override IEnumerator<Move> GetEnumerator&#40;)
&#123;
    // Examine all pieces of the side that just moved in order of piece value descending.
    Moves colMoves;
    // Captures of queens
    colMoves = this.GetCapturesOfPieces&#40;this.Board.Pieces.Queens&#40;this.Board.SideJustMoved&#41;);
    foreach &#40;Move objMove in colMoves&#41;
    &#123;
        // Select move.
        yield return objMove;
    &#125;
    &#91;...&#93;
&#125;
Find attackers of a piece.

Code: Select all

private Moves GetCapturesOfPieces&#40;List<Piece> Pieces&#41;
&#123;
	Moves colMoves = new Moves&#40;);
	foreach &#40;Piece objPiece in Pieces&#41;
	&#123;
		// Determine from which directions piece can be attacked.
		List<Direction> colAttackDirections = this.Board.GetAttackDirections&#40;objPiece.Square, this.Board.SideToMove&#41;;
		// Get attackers.
		List<Piece> colAttackers = this.Board.GetAttackers&#40;objPiece.Square, this.Board.SideToMove, colAttackDirections, false&#41;;
		foreach &#40;Piece objAttacker in colAttackers&#41;
		&#123;
   		     objMove = ...;
		     colMoves.Add&#40;objMove&#41;;
		&#125;                
	&#125;

        &#91;...&#93;

	return colMoves;
&#125;
Hi Erik,

I'm experimenting a bit with incremental move generation. Looking at your code snippet above, you seem to be generating all moves in GetCapturesOfPieces and then returning them one by one with a yield statement in GetEnumerator, correct? I can see how that saves an explicit for loop when you are searching different moves. But you still have an implicit loop over already generated moves. I would have expected that real incremental move generation would use a yield inside GetCapturesOfPieces and "lazily" generate the entire move list to begin with. Have you ever tried to push the yield down all the way to where GetCapturesOfPieces?

Rein
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Question About CPP-C#, Performance, and Square Represena

Post by Don »

Cheney wrote:Thanks for the replies :)

I have VS 2010 Premium and am learning how to use the performance profiler (I think that is what it is called). It is not much help for me now until I understand how to use it.
A crude way to profile is to arrange to call a given routine 2 times instead of one. The time spent in the routine is the difference in the speed between the regular version and the version with the routine called twice.

It's not perfect and will only give a crude measurement mainly because of caching issues but it's better than nothing. You can wrap the function you want to profile in a routine that calls it twice for convenience.

Like I say, it's not perfect but neither are most profiles which insert code to do the profiling, thereby changing it's behavior, sometime in fairly drastic ways.


Some tests I have performed just using stopwatch were to isolate sections of code like move generation and run it in a loop of 1M times and time it. The object based squares compared to bitboards all take the same time an just a few seconds if that.

I do copy the board object and make a move on it to test for legality. I know that recreates all square objects and can be expensive. It alone at 10M iterations in a loop is a few seconds so it did not seem like much.

I made a make/un-make move and ended up with more headaches :) - in the end, it seemed like just as much code as the deep board copy.

One other common item is how I track moves. I actually use the model that ChessBin published. I do not like it. It seem like it is in the way as well.

I found a post in this forum where a move is tracked in an integer. Since I am getting the understanding of bitboards with binary masking I figured I should contine to move in that direction with moves and possibly other items like the board/game state (checks, enp, etc).

Again, thank you for your comments :)
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
User avatar
emadsen
Posts: 434
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: Question About CPP-C#, Performance, and Square Represena

Post by emadsen »

Looking at your code snippet above, you seem to be generating all moves in GetCapturesOfPieces and then returning them one by one with a yield statement in GetEnumerator, correct? I can see how that saves an explicit for loop when you are searching different moves. But you still have an implicit loop over already generated moves. I would have expected that real incremental move generation would use a yield inside GetCapturesOfPieces and "lazily" generate the entire move list to begin with. Have you ever tried to push the yield down all the way to where GetCapturesOfPieces?
I do this to support MVV / LVA move ordering. I get all captures of queens, sort them, iterate over them calling yield. If I yielded inside the GetCapturesOfPieces method I could return a Q x Q before a P x Q, polluting the move order.

My engine uses a mailbox board representation. While I have some attack information available prior to generating moves, it is less detailed than with bitboards. I may know from which of the eight compass directions a queen may be attacked, but I don't know by which piece until I scan outward along the attack vector. Therefore, I must scan all attack vectors and sort the moves to preserve MVV / LVA order, then yield.

My code still saves time avoiding rook captures, bishop captures, etc assuming the queen capture causes a beta cutoff.

Improving attack information is on my to-do list. It could yield better performance, pun intended.
My C# chess engine: https://www.madchess.net