Source file src/cmd/trace/testdata/testprog/main.go

     1  // Copyright 2023 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 main
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"net"
    11  	"os"
    12  	"runtime"
    13  	"runtime/trace"
    14  	"sync"
    15  	"syscall"
    16  	"time"
    17  )
    18  
    19  func main() {
    20  	if err := trace.Start(os.Stdout); err != nil {
    21  		log.Fatal(err)
    22  	}
    23  
    24  	// checkExecutionTimes relies on this.
    25  	var wg sync.WaitGroup
    26  	wg.Add(2)
    27  	go cpu10(&wg)
    28  	go cpu20(&wg)
    29  	wg.Wait()
    30  
    31  	// checkHeapMetrics relies on this.
    32  	allocHog(25 * time.Millisecond)
    33  
    34  	// checkProcStartStop relies on this.
    35  	var wg2 sync.WaitGroup
    36  	for i := 0; i < runtime.GOMAXPROCS(0); i++ {
    37  		wg2.Add(1)
    38  		go func() {
    39  			defer wg2.Done()
    40  			cpuHog(50 * time.Millisecond)
    41  		}()
    42  	}
    43  	wg2.Wait()
    44  
    45  	// checkSyscalls relies on this.
    46  	done := make(chan error)
    47  	go blockingSyscall(50*time.Millisecond, done)
    48  	if err := <-done; err != nil {
    49  		log.Fatal(err)
    50  	}
    51  
    52  	// checkNetworkUnblock relies on this.
    53  	ln, err := net.Listen("tcp", "127.0.0.1:0")
    54  	if err != nil {
    55  		log.Fatalf("listen failed: %v", err)
    56  	}
    57  	defer ln.Close()
    58  	go func() {
    59  		c, err := ln.Accept()
    60  		if err != nil {
    61  			return
    62  		}
    63  		time.Sleep(time.Millisecond)
    64  		var buf [1]byte
    65  		c.Write(buf[:])
    66  		c.Close()
    67  	}()
    68  	c, err := net.Dial("tcp", ln.Addr().String())
    69  	if err != nil {
    70  		log.Fatalf("dial failed: %v", err)
    71  	}
    72  	var tmp [1]byte
    73  	c.Read(tmp[:])
    74  	c.Close()
    75  
    76  	trace.Stop()
    77  }
    78  
    79  // blockingSyscall blocks the current goroutine for duration d in a syscall and
    80  // sends a message to done when it is done or if the syscall failed.
    81  func blockingSyscall(d time.Duration, done chan<- error) {
    82  	r, w, err := os.Pipe()
    83  	if err != nil {
    84  		done <- err
    85  		return
    86  	}
    87  	start := time.Now()
    88  	msg := []byte("hello")
    89  	time.AfterFunc(d, func() { w.Write(msg) })
    90  	_, err = syscall.Read(int(r.Fd()), make([]byte, len(msg)))
    91  	if err == nil && time.Since(start) < d {
    92  		err = fmt.Errorf("syscall returned too early: want=%s got=%s", d, time.Since(start))
    93  	}
    94  	done <- err
    95  }
    96  
    97  func cpu10(wg *sync.WaitGroup) {
    98  	defer wg.Done()
    99  	cpuHog(10 * time.Millisecond)
   100  }
   101  
   102  func cpu20(wg *sync.WaitGroup) {
   103  	defer wg.Done()
   104  	cpuHog(20 * time.Millisecond)
   105  }
   106  
   107  func cpuHog(dt time.Duration) {
   108  	start := time.Now()
   109  	for i := 0; ; i++ {
   110  		if i%1000 == 0 && time.Since(start) > dt {
   111  			return
   112  		}
   113  	}
   114  }
   115  
   116  func allocHog(dt time.Duration) {
   117  	start := time.Now()
   118  	var s [][]byte
   119  	for i := 0; ; i++ {
   120  		if i%1000 == 0 {
   121  			if time.Since(start) > dt {
   122  				return
   123  			}
   124  			// Take a break... this will generate a ton of events otherwise.
   125  			time.Sleep(50 * time.Microsecond)
   126  		}
   127  		s = append(s, make([]byte, 1024))
   128  	}
   129  }
   130  

View as plain text