Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Go doesn't show memory-reordering?

I'm reading preshing's blog Memory Reordering Caught in the Act, and reproduced memory-reordering by his example code

Then I wonder if I could reproduce memory-reordering by Go, so I wrote the example code in go, but memory-reordering is not shown in Go.

I'm writing to share some findings.

And could you help explain why Go could not get memory-reordering? Thanks.

Example code in Go:

 package main

    import (
            "fmt"
            "math/rand"
    )

    var x, y, r1, r2 int
    var detected = 0

    func randWait() {
            for rand.Intn(8) != 0 {
            }
    }

    func main() {
            beginSig1 := make(chan bool, 1)
            beginSig2 := make(chan bool, 1)
            endSig1 := make(chan bool, 1)
            endSig2 := make(chan bool, 1)
            go func() {
                    for {
                            <-beginSig1
                            randWait()
                            x = 1
                            r1 = y
                            endSig1 <- true
                    }
            }()
            go func() {
                    for {
                            <-beginSig2
                            randWait()
                            y = 1
                            r2 = x
                            endSig2 <- true
                    }
            }()
            for i := 1; ; i = i + 1 {
                    x = 0
                    y = 0
                    beginSig1 <- true
                    beginSig2 <- true
                    <-endSig1
                    <-endSig2
                    if r1 == 0 && r2 == 0 {
                            detected = detected + 1
                            fmt.Println(detected, "reorders detected after ", i, "iterations")
                    }
            }
    } 

The assembly code (by "ndisasm -b 32") show different between C++ vs Go

  • Assembly code from C++

    00000CF0  C705520300000100  mov dword [0x352],0x1     //X=1
             -0000
    00000CFA  8B0550030000      mov eax,[0x350]     
    00000D00  89054E030000      mov [0x34e],eax      //r1=Y
    
  • Assembly code from Go

    000013EA  48                dec eax
    000013EB  C70425787F170001  mov dword [0x177f78],0x1     //x=1
             -000000
    000013F6  48                dec eax
    000013F7  8B1C25807F1700    mov ebx,[0x177f80]
    000013FE  48                dec eax
    000013FF  891C25687F1700    mov [0x177f68],ebx          //r1=Y
    00001406  48                dec eax
    

it seems Go uses dec eax around access of shared memory, but it make no sense that dec eax can prevent memory-reordering

  1. The Intel® 64 and IA-32 Architectures Software Developer Manuals Volume 3, Section 8.2 shows the cases that could prevent memory-reordering, but dec eax isn't included...

  2. I tried to add dec eax as margin of shared-memory-access in C code, and memory-reordering is still there.

By now, I have no clue about the reason. Please help me on it, thank you.

like image 717
Tac Huang Avatar asked Nov 11 '13 08:11

Tac Huang


1 Answers

I don't see a call to set GOMAXPROCs anywhere? If you don't call it you'll be running on just one CPU which won't ever show re-ordering: http://golang.org/pkg/runtime/#GOMAXPROCS

Update: In Go 1.5 (Released 2015/08/19) and later you no longer need to set GOMAXPROCS - Go defaults to using all your CPUs.

like image 87
Nick Craig-Wood Avatar answered Sep 21 '22 21:09

Nick Craig-Wood