Source file src/runtime/testdata/testprogcgo/threadpprof.go
1 // Copyright 2016 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 //go:build !plan9 && !windows 6 // +build !plan9,!windows 7 8 package main 9 10 // Run a slow C function saving a CPU profile. 11 12 /* 13 #include <stdint.h> 14 #include <time.h> 15 #include <pthread.h> 16 17 int threadSalt1; 18 int threadSalt2; 19 20 void cpuHogThread() { 21 int foo = threadSalt1; 22 int i; 23 24 for (i = 0; i < 100000; i++) { 25 if (foo > 0) { 26 foo *= foo; 27 } else { 28 foo *= foo + 1; 29 } 30 } 31 threadSalt2 = foo; 32 } 33 34 void cpuHogThread2() { 35 } 36 37 struct cgoTracebackArg { 38 uintptr_t context; 39 uintptr_t sigContext; 40 uintptr_t* buf; 41 uintptr_t max; 42 }; 43 44 // pprofCgoThreadTraceback is passed to runtime.SetCgoTraceback. 45 // For testing purposes it pretends that all CPU hits in C code are in cpuHog. 46 void pprofCgoThreadTraceback(void* parg) { 47 struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg); 48 arg->buf[0] = (uintptr_t)(cpuHogThread) + 0x10; 49 arg->buf[1] = (uintptr_t)(cpuHogThread2) + 0x4; 50 arg->buf[2] = 0; 51 } 52 53 static void* cpuHogDriver(void* arg __attribute__ ((unused))) { 54 while (1) { 55 cpuHogThread(); 56 } 57 return 0; 58 } 59 60 void runCPUHogThread(void) { 61 pthread_t tid; 62 pthread_create(&tid, 0, cpuHogDriver, 0); 63 } 64 */ 65 import "C" 66 67 import ( 68 "context" 69 "fmt" 70 "os" 71 "runtime" 72 "runtime/pprof" 73 "time" 74 "unsafe" 75 ) 76 77 func init() { 78 register("CgoPprofThread", CgoPprofThread) 79 register("CgoPprofThreadNoTraceback", CgoPprofThreadNoTraceback) 80 } 81 82 func CgoPprofThread() { 83 runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoThreadTraceback), nil, nil) 84 pprofThread() 85 } 86 87 func CgoPprofThreadNoTraceback() { 88 pprofThread() 89 } 90 91 func pprofThread() { 92 f, err := os.CreateTemp("", "prof") 93 if err != nil { 94 fmt.Fprintln(os.Stderr, err) 95 os.Exit(2) 96 } 97 98 if err := pprof.StartCPUProfile(f); err != nil { 99 fmt.Fprintln(os.Stderr, err) 100 os.Exit(2) 101 } 102 103 // This goroutine may receive a profiling signal while creating the C-owned 104 // thread. If it does, the SetCgoTraceback handler will make the leaf end of 105 // the stack look almost (but not exactly) like the stacks the test case is 106 // trying to find. Attach a profiler label so the test can filter out those 107 // confusing samples. 108 pprof.Do(context.Background(), pprof.Labels("ignore", "ignore"), func(ctx context.Context) { 109 C.runCPUHogThread() 110 }) 111 112 time.Sleep(1 * time.Second) 113 114 pprof.StopCPUProfile() 115 116 name := f.Name() 117 if err := f.Close(); err != nil { 118 fmt.Fprintln(os.Stderr, err) 119 os.Exit(2) 120 } 121 122 fmt.Println(name) 123 } 124