]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: improve cpu profiles for GC/syscalls/cgo
authorDmitriy Vyukov <dvyukov@google.com>
Wed, 12 Feb 2014 18:31:36 +0000 (22:31 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Wed, 12 Feb 2014 18:31:36 +0000 (22:31 +0400)
Current "System->etext" is not very informative.
Add parent "GC" frame.
Replace un-unwindable syscall/cgo frames with Go stack that leads to the call.

LGTM=rsc
R=rsc, alex.brainman, ality
CC=golang-codereviews
https://golang.org/cl/61270043

src/pkg/runtime/os_windows.c
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h
src/pkg/runtime/sys_windows_386.s
src/pkg/runtime/sys_windows_amd64.s

index d867b0d50e3a32195ea056aca88d838dd354743f..6c9d687b7018a372230457ad333f74f39d652e23 100644 (file)
@@ -291,7 +291,14 @@ runtime·stdcall(void *fn, int32 count, ...)
        m->libcall.fn = fn;
        m->libcall.n = count;
        m->libcall.args = (uintptr*)&count + 1;
+       if(m->profilehz != 0) {
+               // leave pc/sp for cpu profiler
+               m->libcallpc = (uintptr)runtime·getcallerpc(&fn);
+               m->libcallsp = (uintptr)runtime·getcallersp(&fn);
+               m->libcallg = g;
+       }
        runtime·asmcgocall(runtime·asmstdcall, &m->libcall);
+       m->libcallsp = 0;
        return (void*)m->libcall.r1;
 }
 
index c771d5f916a5b99161f181c6388c94f0788ad441..88d6acead3c0da68c0f63c989c4a890b568d7163 100644 (file)
@@ -2104,10 +2104,10 @@ static struct {
        uintptr pcbuf[100];
 } prof;
 
-static void
-System(void)
-{
-}
+static void System(void) {}
+static void ExternalCode(void) {}
+static void GC(void) {}
+extern byte etext[];
 
 // Called if we receive a SIGPROF signal.
 void
@@ -2221,9 +2221,35 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
        if(traceback)
                n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
        if(!traceback || n <= 0) {
-               n = 2;
-               prof.pcbuf[0] = (uintptr)pc;
-               prof.pcbuf[1] = (uintptr)System + 1;
+               // Normal traceback is impossible or has failed.
+               // See if it falls into several common cases.
+               n = 0;
+               if(mp->ncgo > 0 && mp->curg != nil &&
+                       mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) {
+                       // Cgo, we can't unwind and symbolize arbitrary C code,
+                       // so instead collect Go stack that leads to the cgo call.
+                       // This is especially important on windows, since all syscalls are cgo calls.
+                       n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+               }
+#ifdef GOOS_windows
+               if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
+                       // Libcall, i.e. runtime syscall on windows.
+                       // Collect Go stack that leads to the call.
+                       n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+               }
+#endif
+               if(n == 0) {
+                       // If all of the above has failed, account it against abstract "System" or "GC".
+                       n = 2;
+                       // "ExternalCode" is better than "etext".
+                       if((uintptr)pc > (uintptr)etext)
+                               pc = (byte*)ExternalCode + PCQuantum;
+                       prof.pcbuf[0] = (uintptr)pc;
+                       if(mp->gcing || mp->helpgc)
+                               prof.pcbuf[1] = (uintptr)GC + PCQuantum;
+                       else
+                               prof.pcbuf[1] = (uintptr)System + PCQuantum;
+               }
        }
        prof.fn(prof.pcbuf, n);
        runtime·unlock(&prof);
index 57b5329e684950cecc422321c05ae3431826fb25..fa56e30152a0660b4ad6b3cf3331a40425734e07 100644 (file)
@@ -350,6 +350,9 @@ struct      M
        // these are here because they are too large to be on the stack
        // of low-level NOSPLIT functions.
        LibCall libcall;
+       uintptr libcallpc;      // for cpu profiler
+       uintptr libcallsp;
+       G*      libcallg;
 #endif
 #ifdef GOOS_solaris
        int32*  perrno;         // pointer to TLS errno
index 49742c3e04461aeb5fad6bee71fdbb8067a54c47..af10ca8644bc959401dc2d26920c32d8487bd0a2 100644 (file)
@@ -343,19 +343,34 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
        RET
 
        MOVL    m(CX), BP
+
+       // leave pc/sp for cpu profiler
+       MOVL    (SP), SI
+       MOVL    SI, m_libcallpc(BP)
+       LEAL    4(SP), SI
+       MOVL    SI, m_libcallsp(BP)
+       MOVL    g(BP), SI
+       MOVL    SI, m_libcallg(BP)
+
        MOVL    m_g0(BP), SI
        CMPL    g(CX), SI
-       JNE     3(PC)
+       JNE     usleep1_switch
        // executing on m->g0 already
        CALL    AX
-       RET
+       JMP     usleep1_ret
 
+usleep1_switch:
        // Switch to m->g0 stack and back.
        MOVL    (g_sched+gobuf_sp)(SI), SI
        MOVL    SP, -4(SI)
        LEAL    -4(SI), SP
        CALL    AX
        MOVL    0(SP), SP
+
+usleep1_ret:
+       get_tls(CX)
+       MOVL    m(CX), BP
+       MOVL    $0, m_libcallsp(BP)
        RET
 
 // Runs on OS stack. duration (in 100ns units) is in BX.
index cdfde3c61a54a5e058444a98a00ec611c8bcaf30..6576c4283ca2960fa11fce95ecf939ae56909aee 100644 (file)
@@ -337,20 +337,33 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
        CALL    AX
        RET
 
-       MOVQ    m(R15), R14
-       MOVQ    m_g0(R14), R14
+       MOVQ    m(R15), R13
+
+       // leave pc/sp for cpu profiler
+       MOVQ    (SP), R12
+       MOVQ    R12, m_libcallpc(R13)
+       LEAQ    8(SP), R12
+       MOVQ    R12, m_libcallsp(R13)
+       MOVQ    g(R13), R12
+       MOVQ    R12, m_libcallg(R13)
+
+       MOVQ    m_g0(R13), R14
        CMPQ    g(R15), R14
-       JNE     3(PC)
+       JNE     usleep1_switch
        // executing on m->g0 already
        CALL    AX
-       RET
+       JMP     usleep1_ret
 
+usleep1_switch:
        // Switch to m->g0 stack and back.
        MOVQ    (g_sched+gobuf_sp)(R14), R14
        MOVQ    SP, -8(R14)
        LEAQ    -8(R14), SP
        CALL    AX
        MOVQ    0(SP), SP
+
+usleep1_ret:
+       MOVQ    $0, m_libcallsp(R13)
        RET
 
 // Runs on OS stack. duration (in 100ns units) is in BX.