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
5package main
6
7import (
8	"fmt"
9	"log"
10	"net"
11	"os"
12	"runtime"
13	"runtime/trace"
14	"sync"
15	"syscall"
16	"time"
17)
18
19func 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.
81func 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
97func cpu10(wg *sync.WaitGroup) {
98	defer wg.Done()
99	cpuHog(10 * time.Millisecond)
100}
101
102func cpu20(wg *sync.WaitGroup) {
103	defer wg.Done()
104	cpuHog(20 * time.Millisecond)
105}
106
107func 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
116func 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