github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/lfstack_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime_test
     6  
     7  import (
     8  	"math/rand"
     9  	. "runtime"
    10  	"testing"
    11  	"unsafe"
    12  )
    13  
    14  type MyNode struct {
    15  	LFNode
    16  	data int
    17  }
    18  
    19  func fromMyNode(node *MyNode) *LFNode {
    20  	return (*LFNode)(unsafe.Pointer(node))
    21  }
    22  
    23  func toMyNode(node *LFNode) *MyNode {
    24  	return (*MyNode)(unsafe.Pointer(node))
    25  }
    26  
    27  func TestLFStack(t *testing.T) {
    28  	stack := new(uint64)
    29  	// Need to keep additional referenfces to nodes, the stack is not all that type-safe.
    30  	var nodes []*MyNode
    31  
    32  	// Check the stack is initially empty.
    33  	if LFStackPop(stack) != nil {
    34  		t.Fatalf("stack is not empty")
    35  	}
    36  
    37  	// Push one element.
    38  	node := &MyNode{data: 42}
    39  	nodes = append(nodes, node)
    40  	LFStackPush(stack, fromMyNode(node))
    41  
    42  	// Push another.
    43  	node = &MyNode{data: 43}
    44  	nodes = append(nodes, node)
    45  	LFStackPush(stack, fromMyNode(node))
    46  
    47  	// Pop one element.
    48  	node = toMyNode(LFStackPop(stack))
    49  	if node == nil {
    50  		t.Fatalf("stack is empty")
    51  	}
    52  	if node.data != 43 {
    53  		t.Fatalf("no lifo")
    54  	}
    55  
    56  	// Pop another.
    57  	node = toMyNode(LFStackPop(stack))
    58  	if node == nil {
    59  		t.Fatalf("stack is empty")
    60  	}
    61  	if node.data != 42 {
    62  		t.Fatalf("no lifo")
    63  	}
    64  
    65  	// Check the stack is empty again.
    66  	if LFStackPop(stack) != nil {
    67  		t.Fatalf("stack is not empty")
    68  	}
    69  	if *stack != 0 {
    70  		t.Fatalf("stack is not empty")
    71  	}
    72  }
    73  
    74  var stress []*MyNode
    75  
    76  func TestLFStackStress(t *testing.T) {
    77  	const K = 100
    78  	P := 4 * GOMAXPROCS(-1)
    79  	N := 100000
    80  	if testing.Short() {
    81  		N /= 10
    82  	}
    83  	// Create 2 stacks.
    84  	stacks := [2]*uint64{new(uint64), new(uint64)}
    85  	// Need to keep additional references to nodes,
    86  	// the lock-free stack is not type-safe.
    87  	stress = nil
    88  	// Push K elements randomly onto the stacks.
    89  	sum := 0
    90  	for i := 0; i < K; i++ {
    91  		sum += i
    92  		node := &MyNode{data: i}
    93  		stress = append(stress, node)
    94  		LFStackPush(stacks[i%2], fromMyNode(node))
    95  	}
    96  	c := make(chan bool, P)
    97  	for p := 0; p < P; p++ {
    98  		go func() {
    99  			r := rand.New(rand.NewSource(rand.Int63()))
   100  			// Pop a node from a random stack, then push it onto a random stack.
   101  			for i := 0; i < N; i++ {
   102  				node := toMyNode(LFStackPop(stacks[r.Intn(2)]))
   103  				if node != nil {
   104  					LFStackPush(stacks[r.Intn(2)], fromMyNode(node))
   105  				}
   106  			}
   107  			c <- true
   108  		}()
   109  	}
   110  	for i := 0; i < P; i++ {
   111  		<-c
   112  	}
   113  	// Pop all elements from both stacks, and verify that nothing lost.
   114  	sum2 := 0
   115  	cnt := 0
   116  	for i := 0; i < 2; i++ {
   117  		for {
   118  			node := toMyNode(LFStackPop(stacks[i]))
   119  			if node == nil {
   120  				break
   121  			}
   122  			cnt++
   123  			sum2 += node.data
   124  			node.Next = 0
   125  		}
   126  	}
   127  	if cnt != K {
   128  		t.Fatalf("Wrong number of nodes %d/%d", cnt, K)
   129  	}
   130  	if sum2 != sum {
   131  		t.Fatalf("Wrong sum %d/%d", sum2, sum)
   132  	}
   133  
   134  	// Let nodes be collected now.
   135  	stress = nil
   136  }