github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/profiling/profiling_test.go (about)

     1  /*
     2   *
     3   * Copyright 2019 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package profiling
    20  
    21  import (
    22  	"fmt"
    23  	"strconv"
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/hxx258456/ccgo/grpc/internal/grpctest"
    29  	"github.com/hxx258456/ccgo/grpc/internal/profiling/buffer"
    30  )
    31  
    32  type s struct {
    33  	grpctest.Tester
    34  }
    35  
    36  func Test(t *testing.T) {
    37  	grpctest.RunSubTests(t, s{})
    38  }
    39  
    40  func (s) TestProfiling(t *testing.T) {
    41  	cb, err := buffer.NewCircularBuffer(128)
    42  	if err != nil {
    43  		t.Fatalf("error creating circular buffer: %v", err)
    44  	}
    45  
    46  	stat := NewStat("foo")
    47  	cb.Push(stat)
    48  	bar := func(n int) {
    49  		if n%2 == 0 {
    50  			defer stat.NewTimer(strconv.Itoa(n)).Egress()
    51  		} else {
    52  			timer := NewTimer(strconv.Itoa(n))
    53  			stat.AppendTimer(timer)
    54  			defer timer.Egress()
    55  		}
    56  		time.Sleep(1 * time.Microsecond)
    57  	}
    58  
    59  	numTimers := int(8 * defaultStatAllocatedTimers)
    60  	for i := 0; i < numTimers; i++ {
    61  		bar(i)
    62  	}
    63  
    64  	results := cb.Drain()
    65  	if len(results) != 1 {
    66  		t.Fatalf("len(results) = %d; want 1", len(results))
    67  	}
    68  
    69  	statReturned := results[0].(*Stat)
    70  	if stat.Tags != "foo" {
    71  		t.Fatalf("stat.Tags = %s; want foo", stat.Tags)
    72  	}
    73  
    74  	if len(stat.Timers) != numTimers {
    75  		t.Fatalf("len(stat.Timers) = %d; want %d", len(stat.Timers), numTimers)
    76  	}
    77  
    78  	lastIdx := 0
    79  	for i, timer := range statReturned.Timers {
    80  		// Check that they're in the order of append.
    81  		if n, err := strconv.Atoi(timer.Tags); err != nil && n != lastIdx {
    82  			t.Fatalf("stat.Timers[%d].Tags = %s; wanted %d", i, timer.Tags, lastIdx)
    83  		}
    84  
    85  		// Check that the timestamps are consistent.
    86  		if diff := timer.End.Sub(timer.Begin); diff.Nanoseconds() < 1000 {
    87  			t.Fatalf("stat.Timers[%d].End - stat.Timers[%d].Begin = %v; want >= 1000ns", i, i, diff)
    88  		}
    89  
    90  		lastIdx++
    91  	}
    92  }
    93  
    94  func (s) TestProfilingRace(t *testing.T) {
    95  	stat := NewStat("foo")
    96  
    97  	var wg sync.WaitGroup
    98  	numTimers := int(8 * defaultStatAllocatedTimers) // also tests the slice growth code path
    99  	wg.Add(numTimers)
   100  	for i := 0; i < numTimers; i++ {
   101  		go func(n int) {
   102  			defer wg.Done()
   103  			if n%2 == 0 {
   104  				defer stat.NewTimer(strconv.Itoa(n)).Egress()
   105  			} else {
   106  				timer := NewTimer(strconv.Itoa(n))
   107  				stat.AppendTimer(timer)
   108  				defer timer.Egress()
   109  			}
   110  		}(i)
   111  	}
   112  	wg.Wait()
   113  
   114  	if len(stat.Timers) != numTimers {
   115  		t.Fatalf("len(stat.Timers) = %d; want %d", len(stat.Timers), numTimers)
   116  	}
   117  
   118  	// The timers need not be ordered, so we can't expect them to be consecutive
   119  	// like above.
   120  	seen := make(map[int]bool)
   121  	for i, timer := range stat.Timers {
   122  		n, err := strconv.Atoi(timer.Tags)
   123  		if err != nil {
   124  			t.Fatalf("stat.Timers[%d].Tags = %s; wanted integer", i, timer.Tags)
   125  		}
   126  		seen[n] = true
   127  	}
   128  
   129  	for i := 0; i < numTimers; i++ {
   130  		if _, ok := seen[i]; !ok {
   131  			t.Fatalf("seen[%d] = false or does not exist; want it to be true", i)
   132  		}
   133  	}
   134  }
   135  
   136  func BenchmarkProfiling(b *testing.B) {
   137  	for routines := 1; routines <= 1<<8; routines <<= 1 {
   138  		b.Run(fmt.Sprintf("goroutines:%d", routines), func(b *testing.B) {
   139  			perRoutine := b.N / routines
   140  			stat := NewStat("foo")
   141  			var wg sync.WaitGroup
   142  			wg.Add(routines)
   143  			for r := 0; r < routines; r++ {
   144  				go func() {
   145  					for i := 0; i < perRoutine; i++ {
   146  						stat.NewTimer("bar").Egress()
   147  					}
   148  					wg.Done()
   149  				}()
   150  			}
   151  			wg.Wait()
   152  		})
   153  	}
   154  }