mirror of
https://github.com/golang/go
synced 2024-11-21 22:24:40 -07:00
runtime: implement pprof support for windows
Credit to jp for proof of concept. R=alex.brainman, jp, rsc, dvyukov CC=golang-dev https://golang.org/cl/4960057
This commit is contained in:
parent
44f12eb5ad
commit
9fd26872cb
@ -212,6 +212,7 @@ struct G
|
|||||||
uintptr sigcode1;
|
uintptr sigcode1;
|
||||||
uintptr sigpc;
|
uintptr sigpc;
|
||||||
uintptr gopc; // pc of go statement that created this goroutine
|
uintptr gopc; // pc of go statement that created this goroutine
|
||||||
|
uintptr end[];
|
||||||
};
|
};
|
||||||
struct M
|
struct M
|
||||||
{
|
{
|
||||||
@ -253,9 +254,11 @@ struct M
|
|||||||
uint32 fflag; // floating point compare flags
|
uint32 fflag; // floating point compare flags
|
||||||
|
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
|
void* thread; // thread handle
|
||||||
void* event; // event for signalling
|
void* event; // event for signalling
|
||||||
M* nextwaitm; // next M waiting for lock
|
M* nextwaitm; // next M waiting for lock
|
||||||
#endif
|
#endif
|
||||||
|
uintptr end[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stktop
|
struct Stktop
|
||||||
|
@ -10,9 +10,13 @@ enum {
|
|||||||
PROT_EXEC = 0x4,
|
PROT_EXEC = 0x4,
|
||||||
MAP_ANON = 0x1,
|
MAP_ANON = 0x1,
|
||||||
MAP_PRIVATE = 0x2,
|
MAP_PRIVATE = 0x2,
|
||||||
|
DUPLICATE_SAME_ACCESS = 0x2,
|
||||||
|
THREAD_PRIORITY_HIGHEST = 0x2,
|
||||||
SIGINT = 0x2,
|
SIGINT = 0x2,
|
||||||
CTRL_C_EVENT = 0,
|
CTRL_C_EVENT = 0,
|
||||||
CTRL_BREAK_EVENT = 0x1,
|
CTRL_BREAK_EVENT = 0x1,
|
||||||
|
CONTEXT_CONTROL = 0x10001,
|
||||||
|
CONTEXT_FULL = 0x10007,
|
||||||
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
|
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
|
||||||
EXCEPTION_BREAKPOINT = 0x80000003,
|
EXCEPTION_BREAKPOINT = 0x80000003,
|
||||||
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
|
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
|
||||||
|
@ -90,9 +90,7 @@ runtime·sighandler(ExceptionRecord *info, void *frame, Context *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·resetcpuprofiler(int32 hz)
|
runtime·dosigprof(Context *r, G *gp)
|
||||||
{
|
{
|
||||||
// TODO: Enable profiling interrupts.
|
runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp);
|
||||||
|
|
||||||
m->profilehz = hz;
|
|
||||||
}
|
}
|
||||||
|
@ -96,31 +96,52 @@ TEXT runtime·sigtramp1(SB),0,$16-40
|
|||||||
sigdone:
|
sigdone:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// Windows runs the ctrl handler in a new thread.
|
|
||||||
TEXT runtime·ctrlhandler(SB),7,$0
|
TEXT runtime·ctrlhandler(SB),7,$0
|
||||||
|
PUSHL $runtime·ctrlhandler1(SB)
|
||||||
|
CALL runtime·externalthreadhandler(SB)
|
||||||
|
MOVL 4(SP), CX
|
||||||
|
ADDL $12, SP
|
||||||
|
JMP CX
|
||||||
|
|
||||||
|
TEXT runtime·profileloop(SB),7,$0
|
||||||
|
PUSHL $runtime·profileloop1(SB)
|
||||||
|
CALL runtime·externalthreadhandler(SB)
|
||||||
|
MOVL 4(SP), CX
|
||||||
|
ADDL $12, SP
|
||||||
|
JMP CX
|
||||||
|
|
||||||
|
TEXT runtime·externalthreadhandler(SB),7,$0
|
||||||
PUSHL BP
|
PUSHL BP
|
||||||
MOVL SP, BP
|
MOVL SP, BP
|
||||||
PUSHL BX
|
PUSHL BX
|
||||||
PUSHL SI
|
PUSHL SI
|
||||||
PUSHL DI
|
PUSHL DI
|
||||||
PUSHL 0x2c(FS)
|
PUSHL 0x2c(FS)
|
||||||
MOVL SP, BX
|
MOVL SP, DX
|
||||||
|
|
||||||
// setup dummy m, g
|
// setup dummy m, g
|
||||||
SUBL $(m_fflag+4), SP // at least space for m_fflag
|
SUBL $m_end, SP // space for M
|
||||||
|
MOVL SP, 0(SP)
|
||||||
|
MOVL $m_end, 4(SP)
|
||||||
|
CALL runtime·memclr(SB) // smashes AX,BX,CX
|
||||||
|
|
||||||
LEAL m_tls(SP), CX
|
LEAL m_tls(SP), CX
|
||||||
MOVL CX, 0x2c(FS)
|
MOVL CX, 0x2c(FS)
|
||||||
MOVL SP, m(CX)
|
MOVL SP, m(CX)
|
||||||
MOVL SP, DX
|
MOVL SP, BX
|
||||||
SUBL $8, SP // space for g_stack{guard,base}
|
SUBL $g_end, SP // space for G
|
||||||
MOVL SP, g(CX)
|
MOVL SP, g(CX)
|
||||||
MOVL SP, m_g0(DX)
|
MOVL SP, m_g0(BX)
|
||||||
|
|
||||||
|
MOVL SP, 0(SP)
|
||||||
|
MOVL $g_end, 4(SP)
|
||||||
|
CALL runtime·memclr(SB) // smashes AX,BX,CX
|
||||||
LEAL -4096(SP), CX
|
LEAL -4096(SP), CX
|
||||||
MOVL CX, g_stackguard(SP)
|
MOVL CX, g_stackguard(SP)
|
||||||
MOVL BX, g_stackbase(SP)
|
MOVL DX, g_stackbase(SP)
|
||||||
|
|
||||||
PUSHL 8(BP)
|
PUSHL 16(BP) // arg for handler
|
||||||
CALL runtime·ctrlhandler1(SB)
|
CALL 8(BP)
|
||||||
POPL CX
|
POPL CX
|
||||||
|
|
||||||
get_tls(CX)
|
get_tls(CX)
|
||||||
@ -131,9 +152,7 @@ TEXT runtime·ctrlhandler(SB),7,$0
|
|||||||
POPL SI
|
POPL SI
|
||||||
POPL BX
|
POPL BX
|
||||||
POPL BP
|
POPL BP
|
||||||
MOVL 0(SP), CX
|
RET
|
||||||
ADDL $8, SP
|
|
||||||
JMP CX
|
|
||||||
|
|
||||||
// Called from dynamic function created by ../thread.c compilecallback,
|
// Called from dynamic function created by ../thread.c compilecallback,
|
||||||
// running on Windows stack (not Go stack).
|
// running on Windows stack (not Go stack).
|
||||||
|
@ -10,9 +10,13 @@ enum {
|
|||||||
PROT_EXEC = 0x4,
|
PROT_EXEC = 0x4,
|
||||||
MAP_ANON = 0x1,
|
MAP_ANON = 0x1,
|
||||||
MAP_PRIVATE = 0x2,
|
MAP_PRIVATE = 0x2,
|
||||||
|
DUPLICATE_SAME_ACCESS = 0x2,
|
||||||
|
THREAD_PRIORITY_HIGHEST = 0x2,
|
||||||
SIGINT = 0x2,
|
SIGINT = 0x2,
|
||||||
CTRL_C_EVENT = 0,
|
CTRL_C_EVENT = 0,
|
||||||
CTRL_BREAK_EVENT = 0x1,
|
CTRL_BREAK_EVENT = 0x1,
|
||||||
|
CONTEXT_CONTROL = 0x100001,
|
||||||
|
CONTEXT_FULL = 0x10000b,
|
||||||
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
|
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
|
||||||
EXCEPTION_BREAKPOINT = 0x80000003,
|
EXCEPTION_BREAKPOINT = 0x80000003,
|
||||||
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
|
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
|
||||||
|
@ -100,9 +100,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·resetcpuprofiler(int32 hz)
|
runtime·dosigprof(Context *r, G *gp)
|
||||||
{
|
{
|
||||||
// TODO: Enable profiling interrupts.
|
runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp);
|
||||||
|
|
||||||
m->profilehz = hz;
|
|
||||||
}
|
}
|
||||||
|
@ -100,31 +100,51 @@ TEXT runtime·sigtramp(SB),7,$56
|
|||||||
sigdone:
|
sigdone:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// Windows runs the ctrl handler in a new thread.
|
TEXT runtime·ctrlhandler(SB),7,$8
|
||||||
TEXT runtime·ctrlhandler(SB),7,$0
|
MOVQ CX, 16(SP) // spill
|
||||||
|
MOVQ $runtime·ctrlhandler1(SB), CX
|
||||||
|
MOVQ CX, 0(SP)
|
||||||
|
CALL runtime·externalthreadhandler(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT runtime·profileloop(SB),7,$8
|
||||||
|
MOVQ $runtime·profileloop1(SB), CX
|
||||||
|
MOVQ CX, 0(SP)
|
||||||
|
CALL runtime·externalthreadhandler(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT runtime·externalthreadhandler(SB),7,$0
|
||||||
PUSHQ BP
|
PUSHQ BP
|
||||||
MOVQ SP, BP
|
MOVQ SP, BP
|
||||||
PUSHQ BX
|
PUSHQ BX
|
||||||
PUSHQ SI
|
PUSHQ SI
|
||||||
PUSHQ DI
|
PUSHQ DI
|
||||||
PUSHQ 0x58(GS)
|
PUSHQ 0x58(GS)
|
||||||
MOVQ SP, BX
|
MOVQ SP, DX
|
||||||
|
|
||||||
// setup dummy m, g
|
// setup dummy m, g
|
||||||
SUBQ $(m_fflag+4), SP // at least space for m_fflag
|
SUBQ $m_end, SP // space for M
|
||||||
|
MOVQ SP, 0(SP)
|
||||||
|
MOVQ $m_end, 8(SP)
|
||||||
|
CALL runtime·memclr(SB) // smashes AX,BX,CX
|
||||||
|
|
||||||
LEAQ m_tls(SP), CX
|
LEAQ m_tls(SP), CX
|
||||||
MOVQ CX, 0x58(GS)
|
MOVQ CX, 0x58(GS)
|
||||||
MOVQ SP, m(CX)
|
MOVQ SP, m(CX)
|
||||||
MOVQ SP, DX
|
MOVQ SP, BX
|
||||||
SUBQ $16, SP // space for g_stack{guard,base}
|
SUBQ $g_end, SP // space for G
|
||||||
MOVQ SP, g(CX)
|
MOVQ SP, g(CX)
|
||||||
MOVQ SP, m_g0(DX)
|
MOVQ SP, m_g0(BX)
|
||||||
|
|
||||||
|
MOVQ SP, 0(SP)
|
||||||
|
MOVQ $g_end, 8(SP)
|
||||||
|
CALL runtime·memclr(SB) // smashes AX,BX,CX
|
||||||
LEAQ -8192(SP), CX
|
LEAQ -8192(SP), CX
|
||||||
MOVQ CX, g_stackguard(SP)
|
MOVQ CX, g_stackguard(SP)
|
||||||
MOVQ BX, g_stackbase(SP)
|
MOVQ DX, g_stackbase(SP)
|
||||||
|
|
||||||
PUSHQ 16(BP)
|
PUSHQ 32(BP) // arg for handler
|
||||||
CALL runtime·ctrlhandler1(SB)
|
CALL 16(BP)
|
||||||
POPQ CX
|
POPQ CX
|
||||||
|
|
||||||
get_tls(CX)
|
get_tls(CX)
|
||||||
|
@ -17,10 +17,16 @@ enum {
|
|||||||
$MAP_ANON = 1,
|
$MAP_ANON = 1,
|
||||||
$MAP_PRIVATE = 2,
|
$MAP_PRIVATE = 2,
|
||||||
|
|
||||||
|
$DUPLICATE_SAME_ACCESS = DUPLICATE_SAME_ACCESS,
|
||||||
|
$THREAD_PRIORITY_HIGHEST = THREAD_PRIORITY_HIGHEST,
|
||||||
|
|
||||||
$SIGINT = SIGINT,
|
$SIGINT = SIGINT,
|
||||||
$CTRL_C_EVENT = CTRL_C_EVENT,
|
$CTRL_C_EVENT = CTRL_C_EVENT,
|
||||||
$CTRL_BREAK_EVENT = CTRL_BREAK_EVENT,
|
$CTRL_BREAK_EVENT = CTRL_BREAK_EVENT,
|
||||||
|
|
||||||
|
$CONTEXT_CONTROL = CONTEXT_CONTROL,
|
||||||
|
$CONTEXT_FULL = CONTEXT_FULL,
|
||||||
|
|
||||||
$EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION,
|
$EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION,
|
||||||
$EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT,
|
$EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT,
|
||||||
$EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND,
|
$EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND,
|
||||||
|
@ -13,8 +13,8 @@ extern void *runtime·GetProcAddress;
|
|||||||
void runtime·asmstdcall(void *c);
|
void runtime·asmstdcall(void *c);
|
||||||
void *runtime·stdcall(void *fn, int32 count, ...);
|
void *runtime·stdcall(void *fn, int32 count, ...);
|
||||||
|
|
||||||
uintptr runtime·getlasterror(void);
|
uint32 runtime·getlasterror(void);
|
||||||
void runtime·setlasterror(uintptr err);
|
void runtime·setlasterror(uint32 err);
|
||||||
|
|
||||||
// Function to be called by windows CreateThread
|
// Function to be called by windows CreateThread
|
||||||
// to start new os thread.
|
// to start new os thread.
|
||||||
|
@ -10,32 +10,48 @@
|
|||||||
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
|
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
|
||||||
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
|
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
|
||||||
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
|
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
|
||||||
#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
|
#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
|
||||||
#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
|
#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
|
||||||
#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
|
#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
|
||||||
#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
|
#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
|
||||||
#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
|
#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
|
||||||
#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
|
#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
|
||||||
#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
|
#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
|
||||||
#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
|
#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
|
||||||
#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
|
#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
|
||||||
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
|
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
|
||||||
|
#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
|
||||||
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
|
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
|
||||||
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
|
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
|
||||||
|
|
||||||
extern void *runtime·CloseHandle;
|
extern void *runtime·CloseHandle;
|
||||||
extern void *runtime·CreateEvent;
|
extern void *runtime·CreateEvent;
|
||||||
extern void *runtime·CreateThread;
|
extern void *runtime·CreateThread;
|
||||||
|
extern void *runtime·CreateWaitableTimer;
|
||||||
|
extern void *runtime·DuplicateHandle;
|
||||||
extern void *runtime·ExitProcess;
|
extern void *runtime·ExitProcess;
|
||||||
extern void *runtime·FreeEnvironmentStringsW;
|
extern void *runtime·FreeEnvironmentStringsW;
|
||||||
extern void *runtime·GetEnvironmentStringsW;
|
extern void *runtime·GetEnvironmentStringsW;
|
||||||
extern void *runtime·GetProcAddress;
|
extern void *runtime·GetProcAddress;
|
||||||
extern void *runtime·GetStdHandle;
|
extern void *runtime·GetStdHandle;
|
||||||
|
extern void *runtime·GetThreadContext;
|
||||||
extern void *runtime·LoadLibraryEx;
|
extern void *runtime·LoadLibraryEx;
|
||||||
extern void *runtime·QueryPerformanceCounter;
|
extern void *runtime·QueryPerformanceCounter;
|
||||||
extern void *runtime·QueryPerformanceFrequency;
|
extern void *runtime·QueryPerformanceFrequency;
|
||||||
|
extern void *runtime·ResumeThread;
|
||||||
extern void *runtime·SetConsoleCtrlHandler;
|
extern void *runtime·SetConsoleCtrlHandler;
|
||||||
extern void *runtime·SetEvent;
|
extern void *runtime·SetEvent;
|
||||||
|
extern void *runtime·SetThreadPriority;
|
||||||
|
extern void *runtime·SetWaitableTimer;
|
||||||
|
extern void *runtime·SuspendThread;
|
||||||
|
extern void *runtime·timeBeginPeriod;
|
||||||
extern void *runtime·WaitForSingleObject;
|
extern void *runtime·WaitForSingleObject;
|
||||||
extern void *runtime·WriteFile;
|
extern void *runtime·WriteFile;
|
||||||
|
|
||||||
@ -44,8 +60,13 @@ static int64 timerfreq;
|
|||||||
void
|
void
|
||||||
runtime·osinit(void)
|
runtime·osinit(void)
|
||||||
{
|
{
|
||||||
|
// -1 = current process, -2 = current thread
|
||||||
|
runtime·stdcall(runtime·DuplicateHandle, 7,
|
||||||
|
(uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
|
||||||
|
(uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
|
||||||
runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
|
runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
|
||||||
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
|
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
|
||||||
|
runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -211,11 +232,13 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
|
|||||||
USED(g); // assuming g = m->g0
|
USED(g); // assuming g = m->g0
|
||||||
USED(fn); // assuming fn = mstart
|
USED(fn); // assuming fn = mstart
|
||||||
|
|
||||||
thandle = runtime·stdcall(runtime·CreateThread, 6, (uintptr)0, (uintptr)0, runtime·tstart_stdcall, m, (uintptr)0, (uintptr)0);
|
thandle = runtime·stdcall(runtime·CreateThread, 6,
|
||||||
if(thandle == 0) {
|
nil, nil, runtime·tstart_stdcall, m, nil, nil);
|
||||||
|
if(thandle == nil) {
|
||||||
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
|
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
|
||||||
runtime·throw("runtime.newosproc");
|
runtime·throw("runtime.newosproc");
|
||||||
}
|
}
|
||||||
|
runtime·atomicstorep(&m->thread, thandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called to initialize a new m (including the bootstrap m).
|
// Called to initialize a new m (including the bootstrap m).
|
||||||
@ -324,6 +347,89 @@ runtime·ctrlhandler1(uint32 type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void runtime·dosigprof(Context *r, G *gp);
|
||||||
|
extern void runtime·profileloop(void);
|
||||||
|
static void *profiletimer;
|
||||||
|
|
||||||
|
static void
|
||||||
|
profilem(M *mp)
|
||||||
|
{
|
||||||
|
extern M runtime·m0;
|
||||||
|
extern uint32 runtime·tls0[];
|
||||||
|
byte rbuf[sizeof(Context)+15];
|
||||||
|
Context *r;
|
||||||
|
void *tls;
|
||||||
|
G *gp;
|
||||||
|
|
||||||
|
tls = mp->tls;
|
||||||
|
if(mp == &runtime·m0)
|
||||||
|
tls = runtime·tls0;
|
||||||
|
gp = *(G**)tls;
|
||||||
|
|
||||||
|
if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
|
||||||
|
// align Context to 16 bytes
|
||||||
|
r = (Context*)((uintptr)(&rbuf[15]) & ~15);
|
||||||
|
r->ContextFlags = CONTEXT_CONTROL;
|
||||||
|
runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
|
||||||
|
runtime·dosigprof(r, gp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·profileloop1(void)
|
||||||
|
{
|
||||||
|
M *mp, *allm;
|
||||||
|
void *thread;
|
||||||
|
|
||||||
|
runtime·stdcall(runtime·SetThreadPriority, 2,
|
||||||
|
(uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1);
|
||||||
|
allm = runtime·atomicloadp(&runtime·allm);
|
||||||
|
for(mp = allm; mp != nil; mp = mp->alllink) {
|
||||||
|
thread = runtime·atomicloadp(&mp->thread);
|
||||||
|
if(thread == nil)
|
||||||
|
continue;
|
||||||
|
runtime·stdcall(runtime·SuspendThread, 1, thread);
|
||||||
|
if(mp->profilehz != 0)
|
||||||
|
profilem(mp);
|
||||||
|
runtime·stdcall(runtime·ResumeThread, 1, thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·resetcpuprofiler(int32 hz)
|
||||||
|
{
|
||||||
|
static Lock lock;
|
||||||
|
void *timer, *thread;
|
||||||
|
int32 ms;
|
||||||
|
int64 due;
|
||||||
|
|
||||||
|
runtime·lock(&lock);
|
||||||
|
if(profiletimer == nil) {
|
||||||
|
timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil);
|
||||||
|
runtime·atomicstorep(&profiletimer, timer);
|
||||||
|
thread = runtime·stdcall(runtime·CreateThread, 6,
|
||||||
|
nil, nil, runtime·profileloop, nil, nil, nil);
|
||||||
|
runtime·stdcall(runtime·CloseHandle, 1, thread);
|
||||||
|
}
|
||||||
|
runtime·unlock(&lock);
|
||||||
|
|
||||||
|
ms = 0;
|
||||||
|
due = 1LL<<63;
|
||||||
|
if(hz > 0) {
|
||||||
|
ms = 1000 / hz;
|
||||||
|
if(ms == 0)
|
||||||
|
ms = 1;
|
||||||
|
due = ms * -10000;
|
||||||
|
}
|
||||||
|
runtime·stdcall(runtime·SetWaitableTimer, 6,
|
||||||
|
profiletimer, &due, (uintptr)ms, nil, nil, nil);
|
||||||
|
runtime·atomicstore((uint32*)&m->profilehz, hz);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
os·sigpipe(void)
|
os·sigpipe(void)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user