1// Copyright 2018 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// This program outputs a CPU profile that includes
6// both Go and Cgo stacks. This is used by the mapping info
7// tests in runtime/pprof.
8//
9// If SETCGOTRACEBACK=1 is set, the CPU profile will includes
10// PCs from C side but they will not be symbolized.
11package main
12
13/*
14#include <stdint.h>
15#include <stdlib.h>
16
17int cpuHogCSalt1 = 0;
18int cpuHogCSalt2 = 0;
19
20void CPUHogCFunction0(int foo) {
21	int i;
22	for (i = 0; i < 100000; i++) {
23		if (foo > 0) {
24			foo *= foo;
25		} else {
26			foo *= foo + 1;
27		}
28		cpuHogCSalt2 = foo;
29	}
30}
31
32void CPUHogCFunction() {
33	CPUHogCFunction0(cpuHogCSalt1);
34}
35
36struct CgoTracebackArg {
37	uintptr_t context;
38        uintptr_t sigContext;
39	uintptr_t *buf;
40        uintptr_t max;
41};
42
43void CollectCgoTraceback(void* parg) {
44        struct CgoTracebackArg* arg = (struct CgoTracebackArg*)(parg);
45	arg->buf[0] = (uintptr_t)(CPUHogCFunction0);
46	arg->buf[1] = (uintptr_t)(CPUHogCFunction);
47	arg->buf[2] = 0;
48};
49*/
50import "C"
51
52import (
53	"log"
54	"os"
55	"runtime"
56	"runtime/pprof"
57	"time"
58	"unsafe"
59)
60
61func init() {
62	if v := os.Getenv("SETCGOTRACEBACK"); v == "1" {
63		// Collect some PCs from C-side, but don't symbolize.
64		runtime.SetCgoTraceback(0, unsafe.Pointer(C.CollectCgoTraceback), nil, nil)
65	}
66}
67
68func main() {
69	go cpuHogGoFunction()
70	go cpuHogCFunction()
71	runtime.Gosched()
72
73	if err := pprof.StartCPUProfile(os.Stdout); err != nil {
74		log.Fatal("can't start CPU profile: ", err)
75	}
76	time.Sleep(200 * time.Millisecond)
77	pprof.StopCPUProfile()
78
79	if err := os.Stdout.Close(); err != nil {
80		log.Fatal("can't write CPU profile: ", err)
81	}
82}
83
84var salt1 int
85var salt2 int
86
87func cpuHogGoFunction() {
88	for {
89		foo := salt1
90		for i := 0; i < 1e5; i++ {
91			if foo > 0 {
92				foo *= foo
93			} else {
94				foo *= foo + 1
95			}
96			salt2 = foo
97		}
98		runtime.Gosched()
99	}
100}
101
102func cpuHogCFunction() {
103	// Generates CPU profile samples including a Cgo call path.
104	for {
105		C.CPUHogCFunction()
106		runtime.Gosched()
107	}
108}
109