github.com/karlmcguire/casn@v0.0.0-20191208212146-d789ce994bba/casn_test.go (about)

     1  package casn
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"sync"
     7  	"sync/atomic"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  func TestRDCSSRead(t *testing.T) {
    13  	data := []uint64{1, 2}
    14  	if rdcssRead(&data[0]) != 1 || rdcssRead(&data[1]) != 2 {
    15  		t.Fatal("rdcssRead returning wrong values")
    16  	}
    17  }
    18  
    19  func TestGetRDCSSDescriptor(t *testing.T) {
    20  	data := []uint64{0, 0}
    21  	d := &rdcssDescriptor{
    22  		a1: &data[0],
    23  		o1: 0,
    24  		a2: &data[1],
    25  		o2: 0,
    26  		n2: 1,
    27  	}
    28  	if d != getRDCSSDescriptor(d.ptr()) {
    29  		t.Fatal("error")
    30  	}
    31  }
    32  
    33  func TestRDCSS(t *testing.T) {
    34  	control := uint64(0)
    35  	data := uint64(0)
    36  	old := rdcss(&rdcssDescriptor{
    37  		a1: &control,
    38  		o1: 0,
    39  		a2: &data,
    40  		o2: 0,
    41  		n2: 1,
    42  	})
    43  	if old != 0 && data != 1 {
    44  		t.Fatal("RDCSS failed")
    45  	}
    46  }
    47  
    48  func BenchmarkRDCSS(b *testing.B) {
    49  	data := []uint64{0, 0}
    50  	b.SetBytes(1)
    51  	for n := uint64(0); n < uint64(b.N); n++ {
    52  		rdcss(&rdcssDescriptor{
    53  			a1: &data[0],
    54  			o1: 0,
    55  			a2: &data[1],
    56  			o2: n + 0,
    57  			n2: n + 1,
    58  		})
    59  	}
    60  }
    61  
    62  func BenchmarkRDCSSParallel(b *testing.B) {
    63  	data := []uint64{0, 0}
    64  	desc := make([]*rdcssDescriptor, b.N)
    65  	for i := uint64(0); i < uint64(b.N); i++ {
    66  		desc[i] = &rdcssDescriptor{
    67  			a1: &data[0],
    68  			o1: 0,
    69  			a2: &data[1],
    70  			o2: i + 0,
    71  			n2: i + 1,
    72  		}
    73  	}
    74  	b.SetBytes(1)
    75  	b.RunParallel(func(pb *testing.PB) {
    76  		for n := uint64(0); pb.Next(); n++ {
    77  			rdcss(desc[n])
    78  		}
    79  	})
    80  }
    81  
    82  func TestCASN(t *testing.T) {
    83  	data := []uint64{0, 1, 2, 3}
    84  	if CASN([]Update{
    85  		{&data[0], 0, 1},
    86  		{&data[1], 1, 2},
    87  		{&data[2], 2, 3},
    88  		{&data[3], 3, 4},
    89  	}) != true {
    90  		t.Fatal("CASN should be successful")
    91  	}
    92  	if data[0] != 1 || data[1] != 2 || data[2] != 3 || data[3] != 4 {
    93  		t.Fatal("CASN didn't swap values")
    94  	}
    95  	if CASN([]Update{
    96  		{&data[0], 0, 1},
    97  		{&data[1], 1, 2},
    98  		{&data[2], 2, 3},
    99  		{&data[3], 3, 4},
   100  	}) != false {
   101  		t.Fatal("CASN should have failed")
   102  	}
   103  	if data[0] != 1 || data[1] != 2 || data[2] != 3 || data[3] != 4 {
   104  		t.Fatal("CASN shouldn't have swapped values")
   105  	}
   106  }
   107  
   108  func BenchmarkMutex(b *testing.B) {
   109  	data := []uint64{0, 1, 2, 3}
   110  	mu := &sync.Mutex{}
   111  	b.SetBytes(4)
   112  	for n := uint64(0); n < uint64(b.N); n++ {
   113  		mu.Lock()
   114  		data[0] = n + 1
   115  		data[1] = n + 2
   116  		data[2] = n + 3
   117  		data[3] = n + 4
   118  		mu.Unlock()
   119  	}
   120  }
   121  
   122  func BenchmarkMutexParallel(b *testing.B) {
   123  	data := []uint64{0, 1, 2, 3}
   124  	mu := &sync.Mutex{}
   125  	b.SetBytes(4)
   126  	b.RunParallel(func(pb *testing.PB) {
   127  		for n := uint64(0); pb.Next(); n++ {
   128  			mu.Lock()
   129  			data[0] = n + 1
   130  			data[1] = n + 2
   131  			data[2] = n + 3
   132  			data[3] = n + 4
   133  			mu.Unlock()
   134  		}
   135  	})
   136  }
   137  
   138  func BenchmarkCASN(b *testing.B) {
   139  	data := []uint64{0, 1, 2, 3}
   140  	b.SetBytes(4)
   141  	for n := uint64(0); n < uint64(b.N); n++ {
   142  		CASN([]Update{
   143  			{&data[0], n + 0, n + 1},
   144  			{&data[1], n + 1, n + 2},
   145  			{&data[2], n + 2, n + 3},
   146  			{&data[3], n + 3, n + 4},
   147  		})
   148  	}
   149  }
   150  
   151  func BenchmarkCASNParallel(b *testing.B) {
   152  	data := []uint64{0, 1, 2, 3}
   153  	b.SetBytes(4)
   154  	b.RunParallel(func(pb *testing.PB) {
   155  		for n := uint64(0); pb.Next(); n++ {
   156  			CASN([]Update{
   157  				{&data[0], n + 0, n + 1},
   158  				{&data[1], n + 1, n + 2},
   159  				{&data[2], n + 2, n + 3},
   160  				{&data[3], n + 3, n + 4},
   161  			})
   162  		}
   163  	})
   164  }
   165  
   166  func TestCas(t *testing.T) {
   167  	num := uint64(0)
   168  	if old := cas(&num, 0, 1); old != 0 {
   169  		t.Fatal("Cas didn't swap")
   170  	}
   171  	if old := cas(&num, 2, 0); old != 1 {
   172  		t.Fatal("Cas shouldn't have swapped")
   173  	}
   174  }
   175  
   176  func BenchmarkCAS(b *testing.B) {
   177  	data := uint64(0)
   178  	b.SetBytes(1)
   179  	for n := uint64(0); n < uint64(b.N); n++ {
   180  		atomic.CompareAndSwapUint64(&data, n, n+1)
   181  	}
   182  }
   183  
   184  func BenchmarkCASParallel(b *testing.B) {
   185  	data := uint64(0)
   186  	b.SetBytes(1)
   187  	b.RunParallel(func(pb *testing.PB) {
   188  		for n := uint64(0); pb.Next(); n++ {
   189  			atomic.CompareAndSwapUint64(&data, n, n+1)
   190  		}
   191  	})
   192  }
   193  
   194  const (
   195  	V = 1024
   196  	M = V - 1
   197  	N = 4
   198  	P = 8
   199  )
   200  
   201  // BenchmarkEvaluation runs a benchmark most similar to the one found in the
   202  // original paper in order to get an idea of how closely we've followed the
   203  // correct implementation.
   204  func BenchmarkEvaluationCASN(b *testing.B) {
   205  	data := make([]uint64, V)
   206  	ctrl := make([]chan struct{}, P)
   207  	for i := range ctrl {
   208  		ctrl[i] = make(chan struct{})
   209  	}
   210  	for i := 0; i < P; i++ {
   211  		go func(a int) {
   212  			<-ctrl[a]
   213  			r := rand.Int()
   214  			for j := 0; j < V; j++ {
   215  				loc := []int{
   216  					((j + r) + ((V / P) * 0)) & M,
   217  					((j + r) + ((V / P) * 1)) & M,
   218  					((j + r) + ((V / P) * 2)) & M,
   219  					((j + r) + ((V / P) * 3)) & M,
   220  				}
   221  				old := []uint64{
   222  					CASNRead(&data[loc[0]]),
   223  					CASNRead(&data[loc[1]]),
   224  					CASNRead(&data[loc[2]]),
   225  					CASNRead(&data[loc[3]]),
   226  				}
   227  				CASN([]Update{
   228  					{&data[loc[0]], old[0], old[0] + 1},
   229  					{&data[loc[1]], old[1], old[1] + 1},
   230  					{&data[loc[2]], old[2], old[2] + 1},
   231  					{&data[loc[3]], old[3], old[3] + 1},
   232  				})
   233  			}
   234  			ctrl[a] <- struct{}{}
   235  		}(i)
   236  	}
   237  	start := time.Now()
   238  	for i := range ctrl {
   239  		ctrl[i] <- struct{}{}
   240  	}
   241  	for i := range ctrl {
   242  		<-ctrl[i]
   243  	}
   244  	duration := time.Since(start)
   245  	b.ReportMetric(float64(duration/(V*P)), "ns")
   246  	fmt.Println(data)
   247  }