github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/queue/ring_buffer_cursor_test.go (about)

     1  package queue
     2  
     3  import (
     4  	"os"
     5  	"sync"
     6  	"sync/atomic"
     7  	"testing"
     8  	"time"
     9  	"unsafe"
    10  )
    11  
    12  func TestXRingBufferCursor(t *testing.T) {
    13  	cursor := NewXRingBufferCursor()
    14  	beginIs := time.Now()
    15  	for i := 0; i < 100000000; i++ {
    16  		x := cursor.Next()
    17  		if x%10000000 == 0 {
    18  			t.Logf("x=%d", x)
    19  		}
    20  	}
    21  	diff := time.Since(beginIs)
    22  	t.Logf("ts diff=%v", diff)
    23  }
    24  
    25  func TestXRingBufferCursorConcurrency(t *testing.T) {
    26  	_, debugLogDisabled := os.LookupEnv("DISABLE_TEST_DEBUG_LOG")
    27  	// lower than single goroutine test
    28  	cursor := NewXRingBufferCursor()
    29  	t.Logf("cursor size=%v", unsafe.Sizeof(*cursor.(*rbCursor)))
    30  	beginIs := time.Now()
    31  	wg := sync.WaitGroup{}
    32  	wg.Add(10000)
    33  	for i := 0; i < 10000; i++ {
    34  		go func(idx int) {
    35  			for j := 0; j < 10000; j++ {
    36  				x := cursor.Next()
    37  				if x%10000000 == 0 {
    38  					if !debugLogDisabled {
    39  						t.Logf("gid=%d, x=%d", idx, x)
    40  					}
    41  				}
    42  			}
    43  			wg.Done()
    44  		}(i)
    45  	}
    46  	wg.Wait()
    47  	diff := time.Since(beginIs)
    48  	t.Logf("ts diff=%v", diff)
    49  }
    50  
    51  func TestXRingBufferCursorNoPaddingConcurrency(t *testing.T) {
    52  	_, debugLogDisabled := os.LookupEnv("DISABLE_TEST_DEBUG_LOG")
    53  	// Better than padding version
    54  	var cursor uint64 // same address, meaningless for data race
    55  	beginIs := time.Now()
    56  	wg := sync.WaitGroup{}
    57  	wg.Add(10000)
    58  	for i := 0; i < 10000; i++ {
    59  		go func(idx int) {
    60  			for j := 0; j < 10000; j++ {
    61  				x := atomic.AddUint64(&cursor, 1)
    62  				if x%10000000 == 0 {
    63  					if !debugLogDisabled {
    64  						t.Logf("gid=%d, x=%d", idx, x)
    65  					}
    66  				}
    67  			}
    68  			wg.Done()
    69  		}(i)
    70  	}
    71  	wg.Wait()
    72  	diff := time.Since(beginIs)
    73  	t.Logf("ts diff=%v", diff)
    74  }
    75  
    76  type noPaddingObj struct {
    77  	a, b, c uint64
    78  }
    79  
    80  func (o *noPaddingObj) increase() {
    81  	atomic.AddUint64(&o.a, 1)
    82  	atomic.AddUint64(&o.b, 1)
    83  	atomic.AddUint64(&o.c, 1)
    84  }
    85  
    86  type paddingObj struct {
    87  	a uint64
    88  	_ [8]uint64
    89  	b uint64
    90  	_ [8]uint64
    91  	c uint64
    92  	_ [8]uint64
    93  }
    94  
    95  func (o *paddingObj) increase() {
    96  	atomic.AddUint64(&o.a, 1)
    97  	atomic.AddUint64(&o.b, 1)
    98  	atomic.AddUint64(&o.c, 1)
    99  }
   100  
   101  func BenchmarkNoPaddingObj(b *testing.B) {
   102  	// Lower than padding version
   103  	obj := &noPaddingObj{}
   104  	b.RunParallel(func(pb *testing.PB) {
   105  		for pb.Next() {
   106  			obj.increase()
   107  		}
   108  	})
   109  }
   110  
   111  func BenchmarkPaddingObj(b *testing.B) {
   112  	obj := &paddingObj{}
   113  	b.RunParallel(func(pb *testing.PB) {
   114  		for pb.Next() {
   115  			obj.increase()
   116  		}
   117  	})
   118  }
   119  
   120  func TestFalseSharing(t *testing.T) {
   121  	// In the same cache line
   122  	volatileArray := [4]uint64{0, 0, 0, 0} // contiguous memory
   123  	var wg sync.WaitGroup
   124  	wg.Add(4)
   125  	beginIs := time.Now()
   126  	for i := 0; i < 4; i++ {
   127  		// Concurrent write to the same cache line
   128  		// Many cache misses, because of many RFO
   129  		go func(idx int) {
   130  			for j := 0; j < 100000000; j++ {
   131  				atomic.AddUint64(&volatileArray[idx], 1)
   132  			}
   133  			wg.Done()
   134  		}(i)
   135  	}
   136  	wg.Wait()
   137  	diff := time.Since(beginIs)
   138  	// ts diff=8.423525377s
   139  	t.Logf("ts diff=%v", diff)
   140  }
   141  
   142  func TestNoFalseSharing(t *testing.T) {
   143  	type padE struct {
   144  		value uint64
   145  		_     [cacheLinePadSize - unsafe.Sizeof(*new(uint64))]byte
   146  	}
   147  
   148  	// Each one in a different cache line
   149  	volatileArray := [4]padE{{}, {}, {}, {}}
   150  	var wg sync.WaitGroup
   151  	wg.Add(4)
   152  	beginIs := time.Now()
   153  	for i := 0; i < 4; i++ {
   154  		// No RFO data race
   155  		go func(idx int) {
   156  			for j := 0; j < 100000000; j++ {
   157  				atomic.AddUint64(&volatileArray[idx].value, 1)
   158  			}
   159  			wg.Done()
   160  		}(i)
   161  	}
   162  	wg.Wait()
   163  	diff := time.Since(beginIs)
   164  	// ts diff=890.219393ms
   165  	t.Logf("ts diff=%v", diff)
   166  }