Home | History | Annotate | Download | only in testprogcgo
      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 // +build !plan9,!windows
      6 
      7 package main
      8 
      9 // Run a slow C function saving a CPU profile.
     10 
     11 /*
     12 #include <stdint.h>
     13 #include <time.h>
     14 #include <pthread.h>
     15 
     16 int threadSalt1;
     17 int threadSalt2;
     18 
     19 void cpuHogThread() {
     20 	int foo = threadSalt1;
     21 	int i;
     22 
     23 	for (i = 0; i < 100000; i++) {
     24 		if (foo > 0) {
     25 			foo *= foo;
     26 		} else {
     27 			foo *= foo + 1;
     28 		}
     29 	}
     30 	threadSalt2 = foo;
     31 }
     32 
     33 static int cpuHogThreadCount;
     34 
     35 struct cgoTracebackArg {
     36 	uintptr_t  context;
     37 	uintptr_t  sigContext;
     38 	uintptr_t* buf;
     39 	uintptr_t  max;
     40 };
     41 
     42 // pprofCgoThreadTraceback is passed to runtime.SetCgoTraceback.
     43 // For testing purposes it pretends that all CPU hits in C code are in cpuHog.
     44 void pprofCgoThreadTraceback(void* parg) {
     45 	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
     46 	arg->buf[0] = (uintptr_t)(cpuHogThread) + 0x10;
     47 	arg->buf[1] = 0;
     48 	__sync_add_and_fetch(&cpuHogThreadCount, 1);
     49 }
     50 
     51 // getCPUHogThreadCount fetches the number of times we've seen cpuHogThread
     52 // in the traceback.
     53 int getCPUHogThreadCount() {
     54 	return __sync_add_and_fetch(&cpuHogThreadCount, 0);
     55 }
     56 
     57 static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
     58 	while (1) {
     59 		cpuHogThread();
     60 	}
     61 	return 0;
     62 }
     63 
     64 void runCPUHogThread(void) {
     65 	pthread_t tid;
     66 	pthread_create(&tid, 0, cpuHogDriver, 0);
     67 }
     68 */
     69 import "C"
     70 
     71 import (
     72 	"fmt"
     73 	"io/ioutil"
     74 	"os"
     75 	"runtime"
     76 	"runtime/pprof"
     77 	"time"
     78 	"unsafe"
     79 )
     80 
     81 func init() {
     82 	register("CgoPprofThread", CgoPprofThread)
     83 	register("CgoPprofThreadNoTraceback", CgoPprofThreadNoTraceback)
     84 }
     85 
     86 func CgoPprofThread() {
     87 	runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoThreadTraceback), nil, nil)
     88 	pprofThread()
     89 }
     90 
     91 func CgoPprofThreadNoTraceback() {
     92 	pprofThread()
     93 }
     94 
     95 func pprofThread() {
     96 	f, err := ioutil.TempFile("", "prof")
     97 	if err != nil {
     98 		fmt.Fprintln(os.Stderr, err)
     99 		os.Exit(2)
    100 	}
    101 
    102 	if err := pprof.StartCPUProfile(f); err != nil {
    103 		fmt.Fprintln(os.Stderr, err)
    104 		os.Exit(2)
    105 	}
    106 
    107 	C.runCPUHogThread()
    108 
    109 	t0 := time.Now()
    110 	for C.getCPUHogThreadCount() < 2 && time.Since(t0) < time.Second {
    111 		time.Sleep(100 * time.Millisecond)
    112 	}
    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