Move time and compiler optimization

Discussion of chess software programming and technical issues.

Moderator: Ras

mar
Posts: 2663
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Move time and compiler optimization

Post by mar »

Or if you prefer postincrement

Code: Select all

Option(OnChange f) ... idx(f ? counter++ : 0)
syzygy
Posts: 5713
Joined: Tue Feb 28, 2012 11:56 pm

Re: Move time and compiler optimization

Post by syzygy »

mcostalba wrote:
syzygy wrote: You could use a static counter that you increase in the Option() constructor and that you use instead of Options.size().
This won't work (I have tried), but I won't tell you why ;-)
Don't forget to change

Code: Select all

          if (it->second.idx == idx)
into

Code: Select all

          if (it->second.idx == 2 * idx)
:wink:
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Move time and compiler optimization

Post by mcostalba »

syzygy wrote:
mcostalba wrote:
syzygy wrote: You could use a static counter that you increase in the Option() constructor and that you use instead of Options.size().
This won't work (I have tried), but I won't tell you why ;-)
Don't forget to change

Code: Select all

          if (it->second.idx == idx)
into

Code: Select all

          if (it->second.idx == 2 * idx)
:wink:
It is not only this, it is not enough. And of course we are not running for a code obfuscation event ;-)
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Move time and compiler optimization

Post by mcostalba »

Ok I have pushed a patch that removes the trickery from options initializations:

https://github.com/mcostalba/Stockfish/ ... f6649328a5

I failed to stick to this quiz rules because I used another operator '<<' instead of the required '+'.

But at least now solution seems correct.

Thanks also to Rein for his suggestion: I didn't realized such solution was also possible. Nice, although perhaps a bit complex.
Rein Halbersma
Posts: 750
Joined: Tue May 22, 2007 11:13 am

Re: Move time and compiler optimization

Post by Rein Halbersma »

mcostalba wrote:Ok I have pushed a patch that removes the trickery from options initializations:

https://github.com/mcostalba/Stockfish/ ... f6649328a5

I failed to stick to this quiz rules because I used another operator '<<' instead of the required '+'.

But at least now solution seems correct.

Thanks also to Rein for his suggestion: I didn't realized such solution was also possible. Nice, although perhaps a bit complex.
The operator<< approach is short and cute, but maybe too cute ;-) First, it's a bit intrusive to store ordering info in the Option class itself rather than in its map-like container (the Standard Library always uses non-intrusive containers). Second (minor nitpick), you have to be careful never to write something like

Code: Select all

o["bla"] << Option(val1) << Option(val2); 
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Move time and compiler optimization

Post by mcostalba »

Rein Halbersma wrote:
mcostalba wrote:Ok I have pushed a patch that removes the trickery from options initializations:

https://github.com/mcostalba/Stockfish/ ... f6649328a5

I failed to stick to this quiz rules because I used another operator '<<' instead of the required '+'.

But at least now solution seems correct.

Thanks also to Rein for his suggestion: I didn't realized such solution was also possible. Nice, although perhaps a bit complex.
The operator<< approach is short and cute, but maybe too cute ;-) First, it's a bit intrusive to store ordering info in the Option class itself rather than in its map-like container (the Standard Library always uses non-intrusive containers). Second (minor nitpick), you have to be careful never to write something like

Code: Select all

o["bla"] << Option(val1) << Option(val2); 

Yes this member should be private (used only by init) and returning void.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Move time and compiler optimization

Post by bob »

wgarvin wrote:
bob wrote:
mar wrote:I think the point is that the compiler can do whatever optimizations it likes an long as the optimized program behaves exactly the same as if it was synchronized at sequence points.
No argument with one exception. After the inlining stage of the compiler is done, some of the procedure calls are now missing. The compiler sees the inlined code for the actual compilation step, and it is no longer aware of a procedure call, nor of that specific sequence point. Certainly the inlined code will have its own set of sequence points. My comment was simply that the "sequence points" you see MIGHT not exist at all, in reality. Saying "there is a sequence point right here" can, therefore, be a bit inaccurate. In fact, in some cases, a procedure might be removed completely AND not inlined either, if it is found to be useless code. Hence my comment. Nothing more, nothing less.
Sequence points are an abstract thing that exists in the original source program. The compiled program needs to behave "as if" any side effects from before a sequence point, occur before any side effects from after that sequence point. Of course the compiler can mix the instructions together for optimization purposes, as long as the partial ordering of side effects dictated by the sequence points is properly enforced (in single-threaded code, etc. etc.)

If a compiler performs inlining and then during subsequent optimizations, fails to preserve the semantics of the sequence points that originally existed in the source code, then that compiler is broken.
I understand all of that. My point is, if you take a C source, stick your finger in it at point A and say "here is a sequence point in the program" it MIGHT not really be there. That entire block of code might not "be there" in fact. I guess we could call this the "undefined behavior of sequence points" since they are not guaranteed to exist on a 1-to-1 correspondence between what runs and what is in the source.

I get "undone" by this regularly. Write a test case to see what the compiler does, and forget that if the result of the computation is not used, the compiler is free to toss the code away. And it is quite good at recognizing code that is useless.
syzygy
Posts: 5713
Joined: Tue Feb 28, 2012 11:56 pm

Re: Move time and compiler optimization

Post by syzygy »

bob wrote:
wgarvin wrote:
bob wrote:
mar wrote:I think the point is that the compiler can do whatever optimizations it likes an long as the optimized program behaves exactly the same as if it was synchronized at sequence points.
No argument with one exception. After the inlining stage of the compiler is done, some of the procedure calls are now missing. The compiler sees the inlined code for the actual compilation step, and it is no longer aware of a procedure call, nor of that specific sequence point. Certainly the inlined code will have its own set of sequence points. My comment was simply that the "sequence points" you see MIGHT not exist at all, in reality. Saying "there is a sequence point right here" can, therefore, be a bit inaccurate. In fact, in some cases, a procedure might be removed completely AND not inlined either, if it is found to be useless code. Hence my comment. Nothing more, nothing less.
Sequence points are an abstract thing that exists in the original source program. The compiled program needs to behave "as if" any side effects from before a sequence point, occur before any side effects from after that sequence point. Of course the compiler can mix the instructions together for optimization purposes, as long as the partial ordering of side effects dictated by the sequence points is properly enforced (in single-threaded code, etc. etc.)

If a compiler performs inlining and then during subsequent optimizations, fails to preserve the semantics of the sequence points that originally existed in the source code, then that compiler is broken.
I understand all of that. My point is, if you take a C source, stick your finger in it at point A and say "here is a sequence point in the program" it MIGHT not really be there.
In the C source it is really there. The compiler does not rewrite the C source when you are not looking. Write the source, save it, go to sleep, load it in your editor, still there, unchanged.

If you talk about object code, then listen carefully: the C standard does not at all define a concept "sequence point" for object code. Talking about sequence points in object code is a fail.

The question the OP asked is a simple one.
The answer is also a simple one at least for scenario 1.
syzygy wrote:Both receiving I/O and reading system_time involve side effects. A compiler is not allowed to reorder side effects across sequence points. There are sequence points between "blocked wait for message" and the evaluation of "message == go" and between the evaluation of "message == go" and "inital_time = system_time()".

So scenario 1 is impossible.
Impossible if the compiler implements the C standard correctly.

See? No need to talk about sequence points in object code. The question has been answered before we could get into fail territory.

The C-standard concept of sequence point has no meaning for object code, just like the C-standard concept of a volatile variable has no meaning for object code.