Bug #72755 InnoDB mutex spin loop is missing GCC barrier
Submitted: 27 May 2014 2:22 Modified: 30 May 2014 6:22
Reporter: Stewart Smith Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S3 (Non-critical)
Version:5.6 OS:Any
Assigned to: CPU Architecture:Any
Tags: innodb mutex

[27 May 2014 2:22] Stewart Smith
Description:
The spinloop attempting to grab a mutex in innodb lokos like this:

        while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) {
                if (srv_spin_wait_delay) {
                        ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
                }

                i++;
        }

A problem with this is that GCC could optimize this away to nothing if it was sufficiently smart, and indeed, if you remove the ut_delay call, it likely will. It's quite possible that it does do it already with some configurations, and other compilers may do so too.

How to repeat:
Code analysis!

Suggested fix:
Add a GCC barrier inside the loop, like this:
asm volatile("":::"memory");

which forces it not to optimize the loop away to nothing.

I've done this as part of my patch for http://bugs.mysql.com/bug.php?id=72754
[27 May 2014 8:39] MySQL Verification Team
Hello Stewart,

Thank you for the report.

Thanks,
Umesh
[29 May 2014 5:39] Yasufumi Kinoshita
I think "asm volatile("":::"memory");" is not needed here.
Did you actually test the code difference with it and without it?

ut_delay() is function of the another object file ut0ut.o.
And it contains global fake variable access not to be over-optimized.
lock_word is volatile type specified.
I don't think compiler do over-optimization sync0sync.o more to kill the loop.

Or only for srv_spin_wait_delay==0 case?
Or do you use something link-time re-optimization?

Anyway this doesn't seem current problem.
[30 May 2014 6:08] Stewart Smith
I think you're right that for MySQL 5.6 this is not currently a problem.

I've been doing benchmarks with spin_wait_delay=0 on 5.6, but even with spin_wait_delay!=0, the fake variable access is not the most optimal way to implement a delay loop as it generates needless memory traffic - the GCC barrier will force GCC not to optimize the loop away and won't generate excess memory traffic to a global variable (that on Intel will have to be synchronized between CPUs on access).

While I haven't attempted to benchmark it on 5.6, on MySQL 5.7 the memory traffic generated by the MySQL mutex_delay function did show up in a profile and I have a 5.7 patch I'll post very shortly (as in, right now :)
[30 May 2014 6:22] Stewart Smith
For 5.7: http://bugs.mysql.com/bug.php?id=72805 which is generic code, not InnoDB specific.
[14 Apr 2016 0:17] Daniel Black
Commit 5e3efb03 (Bug#20045167) uses a compile barrier as UT_DELAY in the ut_delay loop for arches without a delay/pause instruction.