github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/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  func TestLFStackStress(t *testing.T) {
    75  	const K = 100
    76  	P := 4 * GOMAXPROCS(-1)
    77  	N := 100000
    78  	if testing.Short() {
    79  		N /= 10
    80  	}
    81  	// Create 2 stacks.
    82  	stacks := [2]*uint64{new(uint64), new(uint64)}
    83  	// Need to keep additional referenfces to nodes, the stack is not all that type-safe.
    84  	var nodes []*MyNode
    85  	// Push K elements randomly onto the stacks.
    86  	sum := 0
    87  	for i := 0; i < K; i++ {
    88  		sum += i
    89  		node := &MyNode{data: i}
    90  		nodes = append(nodes, node)
    91  		LFStackPush(stacks[i%2], fromMyNode(node))
    92  	}
    93  	c := make(chan bool, P)
    94  	for p := 0; p < P; p++ {
    95  		go func() {
    96  			r := rand.New(rand.NewSource(rand.Int63()))
    97  			// Pop a node from a random stack, then push it onto a random stack.
    98  			for i := 0; i < N; i++ {
    99  				node := toMyNode(LFStackPop(stacks[r.Intn(2)]))
   100  				if node != nil {
   101  					LFStackPush(stacks[r.Intn(2)], fromMyNode(node))
   102  				}
   103  			}
   104  			c <- true
   105  		}()
   106  	}
   107  	for i := 0; i < P; i++ {
   108  		<-c
   109  	}
   110  	// Pop all elements from both stacks, and verify that nothing lost.
   111  	sum2 := 0
   112  	cnt := 0
   113  	for i := 0; i < 2; i++ {
   114  		for {
   115  			node := toMyNode(LFStackPop(stacks[i]))
   116  			if node == nil {
   117  				break
   118  			}
   119  			cnt++
   120  			sum2 += node.data
   121  			node.Next = nil
   122  		}
   123  	}
   124  	if cnt != K {
   125  		t.Fatalf("Wrong number of nodes %d/%d", cnt, K)
   126  	}
   127  	if sum2 != sum {
   128  		t.Fatalf("Wrong sum %d/%d", sum2, sum)
   129  	}
   130  }