klx wrote: ↑Sat Sep 25, 2021 10:30 pm
So I test ran this in C# (in my Microsoft .NET 6.0, the one you refer to as "Mono"), and didn't see any difference one way or another. I didn't even bother running it in C, since I could tell that the assembly was equivalent.
I don't. I was simply not aware the the "official" MS version was available on windows (haven't been in C# world for a while). The other test runs are done on Windows, though afaik. I wouldn't be surprised if the Windows version of MS stuff performs a tad better (go figure why... ). Would be interesting to see a comparision between the Linux version and the Windows version on the same hardware.
How sure are you about these numbers? How reliable are your times from run to run, is your CPU doing any thermal throttling etc? I was unable to reproduce this difference. It also surprises me, since it seems that the compiler should be able to produce equally fast, or even equal code. (At least clang can and will do this change itself if beneficial.)
i'm using 5.0 not 6.0, maybe they did something in 6.0
Can confirm that replacing the subtraction with xor in the GenRook & GenBishop implementation is worth a full second in .Net 5 on my computer, too.
Spirch' version now has a lot of modifications compared to 1.4 and I plan to revert to 1.4 and add the changes one by one and make separate commits with benchmarks so we can learn what individual changes had the most impact. But I'm not sure when I'll find the time and because this version is so much faster than 1.4 I have for now comitted the code verbatim to the repo.
...that's a really impressive. The C version is only 5s faster...
I have also pushed a new C version based on R.Tomasis changes. It now compiles on Windows and Linux! I didn't end up using the defines for castling and LSB redundancy and decided to go with the version that is most similar to the C# implementation 1.4 (castling changes but no LSB redundancy fix) and in my tests that was not worse performance wise - if anything it's a tad faster.
Minimal Chess (simple, open source, C#) - Youtube & Github Leorik (competitive, in active development, C#) - Github & Lichess
i'm using 5.0 not 6.0, maybe they did something in 6.0
Yeah, I'm just not able to reproduce that difference.
A possible explanation is that the Linux version of .NET is superior to the Windows one and able to do this optimization by itself.
We can already tell that the behavior between Windows and Linux seems different, because the fastest C# version is still over 10 seconds slower than the C version for me -- 19 vs 29 seconds -- which makes C# over 50% slower.
[Moderation warning] This signature violated the rule against commercial exhortations.
klx wrote: ↑Sun Sep 26, 2021 11:49 am
Yeah, I'm just not able to reproduce that difference.
Have you tried using .NET 5? .NET 6 is not officially released, yet. Because besides the fact that you use Linux that's the other major difference I can see.
Minimal Chess (simple, open source, C#) - Youtube & Github Leorik (competitive, in active development, C#) - Github & Lichess
lithander wrote: ↑Sun Sep 26, 2021 1:11 am
I have also pushed a new C version based on R.Tomasis changes. It now compiles on Windows and Linux! I didn't end up using the defines for castling and LSB redundancy and decided to go with the version that is most similar to the C# implementation 1.4 (castling changes but no LSB redundancy fix) and in my tests that was not worse performance wise - if anything it's a tad faster.
Next thing that I'll try doing with the C version is to make sure it also compiles for x86 targets when compiling with MSC. Also, I'd like to see if I can get rid of the warnings. Most of them seem to be related to not having switch cases for all enumeration values. I think I understand why the author did that: switch statements without a default case can be faster. In MSC the recommended (by MS) way to go about that is to use a similar pattern to this:
switch(blah)
{
case 1:
...
break;
case 2:
...
break;
default:
__assume(false);
break;
}
The "always wrong assumption" will tell the compiler that the default case will never be hit and can be optimized away, resulting in faster code. I have to admit however, that I simply do not know if something similar to the MS specific __assume exists for clang or gcc. I'll have to google a little bit here.
klx wrote: ↑Sun Sep 26, 2021 11:49 am
We can already tell that the behavior between Windows and Linux seems different, because the fastest C# version is still over 10 seconds slower than the C version for me -- 19 vs 29 seconds -- which makes C# over 50% slower.
I'm back home now, so that I can use my developement machine where I can run more accurate tests than on the laptop where I have no control over thermal throttling. It's a 10th gen. Intel i9 with a custom watercooling loop. That allows me to fix the clock speed and the CPU itself also will almost never trigger any thermal throttling. I will run a comparision of the windows and linux version to get exact figures. Linux version will run against WSL, though, but I'm rather confident it will behave like a pure linux system, since it is the same ubuntu kernel.
I've looked into the modifications made by spirch and I'm not sure how you all feel about his changes away from the TMove struct to encoding all move properties in an int instead and using constants instead of the TPieceType enum?
I think I can reach the same speed without making these fundamental changes to how 1.4 was (and also the C version is). What would you prefer in the repo?
And I found another improvement to the Illegal() function putting my C# version close to 60M NPS.
lithander wrote: ↑Mon Sep 27, 2021 12:36 pm
I've looked into the modifications made by spirch and I'm not sure how you all feel about his changes away from the TMove struct to encoding all move properties in an int instead and using constants instead of the TPieceType enum?
I think I can reach the same speed without making these fundamental changes to how 1.4 was (and also the C version is). What would you prefer in the repo?
I would say if the difference is measureable then go with whatever is faster. In the C version the move structure is a union which also maps to an int, so I guess nothing unfair about it. If the difference isn't really measurable then stick with whatever is closer to the original C.
don't forget that struct in c++ != struct in c# so by default it's not the same
(if i remember correctly, struct in c++ are more like class in c# anyway, a quick search could prove or disprove it haha)
enum are using runtime resource while constant are not
spirch wrote: ↑Mon Sep 27, 2021 1:37 pm
don't forget that struct in c++ != struct in c# so by default it's not the same
(if i remember correctly, struct in c++ are more like class in c# anyway, a quick search could prove or disprove it haha)
Afaik a struct in C++ behaves exactly like a class, the only difference being that members are public instead of private by default. However the C/C++ version of our experiment is pure C. So no classes anyway, which makes the destinction a moot point.
Last edited by R. Tomasi on Mon Sep 27, 2021 1:53 pm, edited 1 time in total.