1
2
3
4
5 package main
6
7
8
9
10
22 import "C"
23
24 import (
25 "fmt"
26 "io"
27 "runtime"
28 "runtime/pprof"
29 "sync"
30 "sync/atomic"
31 "unsafe"
32 )
33
34 func init() {
35 register("TracebackContext", TracebackContext)
36 register("TracebackContextPreemption", TracebackContextPreemption)
37 register("TracebackContextProfile", TracebackContextProfile)
38 }
39
40 var tracebackOK bool
41
42 func TracebackContext() {
43 runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
44 C.C1()
45 if got := C.getContextCount(); got != 0 {
46 fmt.Printf("at end contextCount == %d, expected 0\n", got)
47 tracebackOK = false
48 }
49 if tracebackOK {
50 fmt.Println("OK")
51 }
52 }
53
54
55 func G1() {
56 C.C2()
57 }
58
59
60 func G2() {
61 pc := make([]uintptr, 32)
62 n := runtime.Callers(0, pc)
63 cf := runtime.CallersFrames(pc[:n])
64 var frames []runtime.Frame
65 for {
66 frame, more := cf.Next()
67 frames = append(frames, frame)
68 if !more {
69 break
70 }
71 }
72
73 want := []struct {
74 function string
75 line int
76 }{
77 {"main.G2", 0},
78 {"cFunction", 0x10200},
79 {"cFunction", 0x200},
80 {"cFunction", 0x10201},
81 {"cFunction", 0x201},
82 {"main.G1", 0},
83 {"cFunction", 0x10100},
84 {"cFunction", 0x100},
85 {"main.TracebackContext", 0},
86 }
87
88 ok := true
89 i := 0
90 wantLoop:
91 for _, w := range want {
92 for ; i < len(frames); i++ {
93 if w.function == frames[i].Function {
94 if w.line != 0 && w.line != frames[i].Line {
95 fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line)
96 ok = false
97 }
98 i++
99 continue wantLoop
100 }
101 }
102 fmt.Printf("did not find function %s in\n", w.function)
103 for _, f := range frames {
104 fmt.Println(f)
105 }
106 ok = false
107 break
108 }
109 tracebackOK = ok
110 if got := C.getContextCount(); got != 2 {
111 fmt.Printf("at bottom contextCount == %d, expected 2\n", got)
112 tracebackOK = false
113 }
114 }
115
116
117 func TracebackContextPreemption() {
118 runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContextSimple), unsafe.Pointer(C.tcSymbolizer))
119
120 const funcs = 10
121 const calls = 1e5
122 var wg sync.WaitGroup
123 for i := 0; i < funcs; i++ {
124 wg.Add(1)
125 go func(i int) {
126 defer wg.Done()
127 for j := 0; j < calls; j++ {
128 C.TracebackContextPreemptionCallGo(C.int(i*calls + j))
129 }
130 }(i)
131 }
132 wg.Wait()
133
134 fmt.Println("OK")
135 }
136
137
138 func TracebackContextPreemptionGoFunction(i C.int) {
139
140 fmt.Sprintf("%d\n", i)
141 }
142
143
144
145
146
147 func TracebackContextProfile() {
148 runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContextSimple), unsafe.Pointer(C.tcSymbolizer))
149
150 if err := pprof.StartCPUProfile(io.Discard); err != nil {
151 panic(fmt.Sprintf("error starting CPU profile: %v", err))
152 }
153 defer pprof.StopCPUProfile()
154
155 const calls = 1e5
156 var wg sync.WaitGroup
157 for i := 0; i < runtime.GOMAXPROCS(0); i++ {
158 wg.Add(1)
159 go func() {
160 defer wg.Done()
161 for j := 0; j < calls; j++ {
162 C.TracebackContextProfileCallGo()
163 }
164 }()
165 }
166 wg.Wait()
167
168 fmt.Println("OK")
169 }
170
171 var sink atomic.Pointer[byte]
172
173
174 func TracebackContextProfileGoFunction() {
175
176
177 b := make([]byte, 128)
178 sink.Store(&b[0])
179 }
180
View as plain text