runtime: copy mprof code from Go 1.7 runtime
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 14 Oct 2016 22:51:46 +0000 (22:51 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 14 Oct 2016 22:51:46 +0000 (22:51 +0000)
    Also create a gccgo version of some of the traceback code in
    traceback_gccgo.go, replacing some code currently in C.

    This required modifying the compiler so that when compiling the runtime
    package a slice expression does not cause a local array variable to
    escape to the heap.

    Reviewed-on: https://go-review.googlesource.com/31230

From-SVN: r241189

16 files changed:
gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
libgo/Makefile.am
libgo/Makefile.in
libgo/go/runtime/debug.go
libgo/go/runtime/mprof.go [new file with mode: 0644]
libgo/go/runtime/runtime2.go
libgo/go/runtime/stubs.go
libgo/go/runtime/traceback_gccgo.go [new file with mode: 0644]
libgo/runtime/go-traceback.c [deleted file]
libgo/runtime/malloc.h
libgo/runtime/mgc0.c
libgo/runtime/mprof.goc [deleted file]
libgo/runtime/proc.c
libgo/runtime/runtime.c
libgo/runtime/runtime.h

index b2f0413da895d241fdd9de1a532d77716d349a27..2e09ec1db85a37443e12f0813e54587d86bbd8d9 100644 (file)
@@ -1,4 +1,4 @@
-993840643e27e52cda7e86e6a775f54443ea5d07
+ec3dc927da71d15cac48a13c0fb0c1f94572d0d2
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index daa1c92cce6b4167f2b4cccd9a8ef7e974d612db..261129faa0c99f41f597b9696c4732fb005d51d0 100644 (file)
@@ -10308,7 +10308,7 @@ Array_index_expression::do_determine_type(const Type_context*)
 // Check types of an array index.
 
 void
-Array_index_expression::do_check_types(Gogo*)
+Array_index_expression::do_check_types(Gogo* gogo)
 {
   Numeric_constant nc;
   unsigned long v;
@@ -10427,7 +10427,18 @@ Array_index_expression::do_check_types(Gogo*)
       if (!this->array_->is_addressable())
        this->report_error(_("slice of unaddressable value"));
       else
-       this->array_->address_taken(true);
+       {
+         bool escapes = true;
+
+         // When compiling the runtime, a slice operation does not
+         // cause local variables to escape.  When escape analysis
+         // becomes the default, this should be changed to make it an
+         // error if we have a slice operation that escapes.
+         if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
+           escapes = false;
+
+         this->array_->address_taken(escapes);
+       }
     }
 }
 
index dee6fbcc25cba7509e8e4c10d23ea532c0709854..f90331fc5292b887fe1cab351003f0cf5b644650 100644 (file)
@@ -478,7 +478,6 @@ runtime_files = \
        runtime/go-signal.c \
        runtime/go-strcmp.c \
        runtime/go-strslice.c \
-       runtime/go-traceback.c \
        runtime/go-type-complex.c \
        runtime/go-type-eface.c \
        runtime/go-type-float.c \
@@ -515,7 +514,6 @@ runtime_files = \
        go-iface.c \
        lfstack.c \
        malloc.c \
-       mprof.c \
        netpoll.c \
        rdebug.c \
        reflect.c \
index c811312f21d69c5da9d2bfe13ee81cff4695eedb..1955ede5b5dd200226389222d9bba2db0c836fa6 100644 (file)
@@ -253,17 +253,17 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
        go-nanotime.lo go-now.lo go-new.lo go-nosys.lo go-panic.lo \
        go-recover.lo go-reflect-call.lo go-runtime-error.lo \
        go-setenv.lo go-signal.lo go-strcmp.lo go-strslice.lo \
-       go-traceback.lo go-type-complex.lo go-type-eface.lo \
-       go-type-float.lo go-type-identity.lo go-type-interface.lo \
-       go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
-       go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
-       go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo mcache.lo \
-       mcentral.lo $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo \
-       msize.lo $(am__objects_2) panic.lo parfor.lo print.lo proc.lo \
+       go-type-complex.lo go-type-eface.lo go-type-float.lo \
+       go-type-identity.lo go-type-interface.lo go-type-string.lo \
+       go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \
+       go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \
+       env_posix.lo heapdump.lo mcache.lo mcentral.lo \
+       $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \
+       $(am__objects_2) panic.lo parfor.lo print.lo proc.lo \
        runtime.lo signal_unix.lo thread.lo $(am__objects_3) yield.lo \
-       $(am__objects_4) go-iface.lo lfstack.lo malloc.lo mprof.lo \
-       netpoll.lo rdebug.lo reflect.lo runtime1.lo sigqueue.lo \
-       time.lo $(am__objects_5)
+       $(am__objects_4) go-iface.lo lfstack.lo malloc.lo netpoll.lo \
+       rdebug.lo reflect.lo runtime1.lo sigqueue.lo time.lo \
+       $(am__objects_5)
 am_libgo_llgo_la_OBJECTS = $(am__objects_6)
 libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
 libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -877,7 +877,6 @@ runtime_files = \
        runtime/go-signal.c \
        runtime/go-strcmp.c \
        runtime/go-strslice.c \
-       runtime/go-traceback.c \
        runtime/go-type-complex.c \
        runtime/go-type-eface.c \
        runtime/go-type-float.c \
@@ -914,7 +913,6 @@ runtime_files = \
        go-iface.c \
        lfstack.c \
        malloc.c \
-       mprof.c \
        netpoll.c \
        rdebug.c \
        reflect.c \
@@ -1593,7 +1591,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-traceback.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-complex.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-eface.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-float.Plo@am__quote@
@@ -1620,7 +1617,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfixalloc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgc0.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprof.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msize.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_epoll.Plo@am__quote@
@@ -1986,13 +1982,6 @@ go-strslice.lo: runtime/go-strslice.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
 
-go-traceback.lo: runtime/go-traceback.c
-@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-traceback.lo -MD -MP -MF $(DEPDIR)/go-traceback.Tpo -c -o go-traceback.lo `test -f 'runtime/go-traceback.c' || echo '$(srcdir)/'`runtime/go-traceback.c
-@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-traceback.Tpo $(DEPDIR)/go-traceback.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-traceback.c' object='go-traceback.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-traceback.lo `test -f 'runtime/go-traceback.c' || echo '$(srcdir)/'`runtime/go-traceback.c
-
 go-type-complex.lo: runtime/go-type-complex.c
 @am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-complex.lo -MD -MP -MF $(DEPDIR)/go-type-complex.Tpo -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
 @am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-type-complex.Tpo $(DEPDIR)/go-type-complex.Plo
index 56d19d7a4cf973f1f5628c48022b8b98e9b69421..56e307fb3f553886783ec9aa9bf23dff9c9e4bde 100644 (file)
@@ -4,18 +4,6 @@
 
 package runtime
 
-// Breakpoint executes a breakpoint trap.
-func Breakpoint()
-
-// LockOSThread wires the calling goroutine to its current operating system thread.
-// Until the calling goroutine exits or calls UnlockOSThread, it will always
-// execute in that thread, and no other goroutine can.
-func LockOSThread()
-
-// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
-// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
-func UnlockOSThread()
-
 // GOMAXPROCS sets the maximum number of CPUs that can be executing
 // simultaneously and returns the previous setting. If n < 1, it does not
 // change the current setting.
@@ -36,145 +24,6 @@ func NumCgoCall() int64
 // NumGoroutine returns the number of goroutines that currently exist.
 func NumGoroutine() int
 
-// MemProfileRate controls the fraction of memory allocations
-// that are recorded and reported in the memory profile.
-// The profiler aims to sample an average of
-// one allocation per MemProfileRate bytes allocated.
-//
-// To include every allocated block in the profile, set MemProfileRate to 1.
-// To turn off profiling entirely, set MemProfileRate to 0.
-//
-// The tools that process the memory profiles assume that the
-// profile rate is constant across the lifetime of the program
-// and equal to the current value.  Programs that change the
-// memory profiling rate should do so just once, as early as
-// possible in the execution of the program (for example,
-// at the beginning of main).
-var MemProfileRate int = 512 * 1024
-
-// A MemProfileRecord describes the live objects allocated
-// by a particular call sequence (stack trace).
-type MemProfileRecord struct {
-       AllocBytes, FreeBytes     int64       // number of bytes allocated, freed
-       AllocObjects, FreeObjects int64       // number of objects allocated, freed
-       Stack0                    [32]uintptr // stack trace for this record; ends at first 0 entry
-}
-
-// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
-func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
-
-// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
-func (r *MemProfileRecord) InUseObjects() int64 {
-       return r.AllocObjects - r.FreeObjects
-}
-
-// Stack returns the stack trace associated with the record,
-// a prefix of r.Stack0.
-func (r *MemProfileRecord) Stack() []uintptr {
-       for i, v := range r.Stack0 {
-               if v == 0 {
-                       return r.Stack0[0:i]
-               }
-       }
-       return r.Stack0[0:]
-}
-
-// MemProfile returns n, the number of records in the current memory profile.
-// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
-// If len(p) < n, MemProfile does not change p and returns n, false.
-//
-// If inuseZero is true, the profile includes allocation records
-// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
-// These are sites where memory was allocated, but it has all
-// been released back to the runtime.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.memprofile flag instead
-// of calling MemProfile directly.
-func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
-
-// A StackRecord describes a single execution stack.
-type StackRecord struct {
-       Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
-}
-
-// Stack returns the stack trace associated with the record,
-// a prefix of r.Stack0.
-func (r *StackRecord) Stack() []uintptr {
-       for i, v := range r.Stack0 {
-               if v == 0 {
-                       return r.Stack0[0:i]
-               }
-       }
-       return r.Stack0[0:]
-}
-
-// ThreadCreateProfile returns n, the number of records in the thread creation profile.
-// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true.
-// If len(p) < n, ThreadCreateProfile does not change p and returns n, false.
-//
-// Most clients should use the runtime/pprof package instead
-// of calling ThreadCreateProfile directly.
-func ThreadCreateProfile(p []StackRecord) (n int, ok bool)
-
-// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
-// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
-// If len(p) < n, GoroutineProfile does not change p and returns n, false.
-//
-// Most clients should use the runtime/pprof package instead
-// of calling GoroutineProfile directly.
-func GoroutineProfile(p []StackRecord) (n int, ok bool)
-
-// CPUProfile returns the next chunk of binary CPU profiling stack trace data,
-// blocking until data is available.  If profiling is turned off and all the profile
-// data accumulated while it was on has been returned, CPUProfile returns nil.
-// The caller must save the returned data before calling CPUProfile again.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.cpuprofile flag instead of calling
-// CPUProfile directly.
-func CPUProfile() []byte
-
-// SetCPUProfileRate sets the CPU profiling rate to hz samples per second.
-// If hz <= 0, SetCPUProfileRate turns off profiling.
-// If the profiler is on, the rate cannot be changed without first turning it off.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.cpuprofile flag instead of calling
-// SetCPUProfileRate directly.
-func SetCPUProfileRate(hz int)
-
-// SetBlockProfileRate controls the fraction of goroutine blocking events
-// that are reported in the blocking profile.  The profiler aims to sample
-// an average of one blocking event per rate nanoseconds spent blocked.
-//
-// To include every blocking event in the profile, pass rate = 1.
-// To turn off profiling entirely, pass rate <= 0.
-func SetBlockProfileRate(rate int)
-
-// BlockProfileRecord describes blocking events originated
-// at a particular call sequence (stack trace).
-type BlockProfileRecord struct {
-       Count  int64
-       Cycles int64
-       StackRecord
-}
-
-// BlockProfile returns n, the number of records in the current blocking profile.
-// If len(p) >= n, BlockProfile copies the profile into p and returns n, true.
-// If len(p) < n, BlockProfile does not change p and returns n, false.
-//
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.blockprofile flag instead
-// of calling BlockProfile directly.
-func BlockProfile(p []BlockProfileRecord) (n int, ok bool)
-
-// Stack formats a stack trace of the calling goroutine into buf
-// and returns the number of bytes written to buf.
-// If all is true, Stack formats stack traces of all other goroutines
-// into buf after the trace for the current goroutine.
-func Stack(buf []byte, all bool) int
-
 // Get field tracking information.  Only fields with a tag go:"track"
 // are tracked.  This function will add every such field that is
 // referenced to the map.  The keys in the map will be
diff --git a/libgo/go/runtime/mprof.go b/libgo/go/runtime/mprof.go
new file mode 100644 (file)
index 0000000..8d11031
--- /dev/null
@@ -0,0 +1,689 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc profiling.
+// Patterned after tcmalloc's algorithms; shorter code.
+
+package runtime
+
+import (
+       "runtime/internal/atomic"
+       "unsafe"
+)
+
+// Export temporarily for gccgo's C code to call:
+//go:linkname mProf_Malloc runtime.mProf_Malloc
+//go:linkname mProf_Free runtime.mProf_Free
+//go:linkname mProf_GC runtime.mProf_GC
+//go:linkname tracealloc runtime.tracealloc
+//go:linkname tracefree runtime.tracefree
+//go:linkname tracegc runtime.tracegc
+//go:linkname iterate_memprof runtime.iterate_memprof
+
+// NOTE(rsc): Everything here could use cas if contention became an issue.
+var proflock mutex
+
+// All memory allocations are local and do not escape outside of the profiler.
+// The profiler is forbidden from referring to garbage-collected memory.
+
+const (
+       // profile types
+       memProfile bucketType = 1 + iota
+       blockProfile
+
+       // size of bucket hash table
+       buckHashSize = 179999
+
+       // max depth of stack to record in bucket
+       maxStack = 32
+)
+
+type bucketType int
+
+// A bucket holds per-call-stack profiling information.
+// The representation is a bit sleazy, inherited from C.
+// This struct defines the bucket header. It is followed in
+// memory by the stack words and then the actual record
+// data, either a memRecord or a blockRecord.
+//
+// Per-call-stack profiling information.
+// Lookup by hashing call stack into a linked-list hash table.
+type bucket struct {
+       next    *bucket
+       allnext *bucket
+       typ     bucketType // memBucket or blockBucket
+       hash    uintptr
+       size    uintptr
+       nstk    uintptr
+}
+
+// A memRecord is the bucket data for a bucket of type memProfile,
+// part of the memory profile.
+type memRecord struct {
+       // The following complex 3-stage scheme of stats accumulation
+       // is required to obtain a consistent picture of mallocs and frees
+       // for some point in time.
+       // The problem is that mallocs come in real time, while frees
+       // come only after a GC during concurrent sweeping. So if we would
+       // naively count them, we would get a skew toward mallocs.
+       //
+       // Mallocs are accounted in recent stats.
+       // Explicit frees are accounted in recent stats.
+       // GC frees are accounted in prev stats.
+       // After GC prev stats are added to final stats and
+       // recent stats are moved into prev stats.
+       allocs      uintptr
+       frees       uintptr
+       alloc_bytes uintptr
+       free_bytes  uintptr
+
+       // changes between next-to-last GC and last GC
+       prev_allocs      uintptr
+       prev_frees       uintptr
+       prev_alloc_bytes uintptr
+       prev_free_bytes  uintptr
+
+       // changes since last GC
+       recent_allocs      uintptr
+       recent_frees       uintptr
+       recent_alloc_bytes uintptr
+       recent_free_bytes  uintptr
+}
+
+// A blockRecord is the bucket data for a bucket of type blockProfile,
+// part of the blocking profile.
+type blockRecord struct {
+       count  int64
+       cycles int64
+}
+
+var (
+       mbuckets  *bucket // memory profile buckets
+       bbuckets  *bucket // blocking profile buckets
+       buckhash  *[179999]*bucket
+       bucketmem uintptr
+)
+
+// newBucket allocates a bucket with the given type and number of stack entries.
+func newBucket(typ bucketType, nstk int) *bucket {
+       size := unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(location{})
+       switch typ {
+       default:
+               throw("invalid profile bucket type")
+       case memProfile:
+               size += unsafe.Sizeof(memRecord{})
+       case blockProfile:
+               size += unsafe.Sizeof(blockRecord{})
+       }
+
+       b := (*bucket)(persistentalloc(size, 0, &memstats.buckhash_sys))
+       bucketmem += size
+       b.typ = typ
+       b.nstk = uintptr(nstk)
+       return b
+}
+
+// stk returns the slice in b holding the stack.
+func (b *bucket) stk() []location {
+       stk := (*[maxStack]location)(add(unsafe.Pointer(b), unsafe.Sizeof(*b)))
+       return stk[:b.nstk:b.nstk]
+}
+
+// mp returns the memRecord associated with the memProfile bucket b.
+func (b *bucket) mp() *memRecord {
+       if b.typ != memProfile {
+               throw("bad use of bucket.mp")
+       }
+       data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(location{}))
+       return (*memRecord)(data)
+}
+
+// bp returns the blockRecord associated with the blockProfile bucket b.
+func (b *bucket) bp() *blockRecord {
+       if b.typ != blockProfile {
+               throw("bad use of bucket.bp")
+       }
+       data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(location{}))
+       return (*blockRecord)(data)
+}
+
+// Return the bucket for stk[0:nstk], allocating new bucket if needed.
+func stkbucket(typ bucketType, size uintptr, stk []location, alloc bool) *bucket {
+       if buckhash == nil {
+               buckhash = (*[buckHashSize]*bucket)(sysAlloc(unsafe.Sizeof(*buckhash), &memstats.buckhash_sys))
+               if buckhash == nil {
+                       throw("runtime: cannot allocate memory")
+               }
+       }
+
+       // Hash stack.
+       var h uintptr
+       for _, loc := range stk {
+               h += loc.pc
+               h += h << 10
+               h ^= h >> 6
+       }
+       // hash in size
+       h += size
+       h += h << 10
+       h ^= h >> 6
+       // finalize
+       h += h << 3
+       h ^= h >> 11
+
+       i := int(h % buckHashSize)
+       for b := buckhash[i]; b != nil; b = b.next {
+               if b.typ == typ && b.hash == h && b.size == size && eqslice(b.stk(), stk) {
+                       return b
+               }
+       }
+
+       if !alloc {
+               return nil
+       }
+
+       // Create new bucket.
+       b := newBucket(typ, len(stk))
+       copy(b.stk(), stk)
+       b.hash = h
+       b.size = size
+       b.next = buckhash[i]
+       buckhash[i] = b
+       if typ == memProfile {
+               b.allnext = mbuckets
+               mbuckets = b
+       } else {
+               b.allnext = bbuckets
+               bbuckets = b
+       }
+       return b
+}
+
+func eqslice(x, y []location) bool {
+       if len(x) != len(y) {
+               return false
+       }
+       for i, xi := range x {
+               if xi != y[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+func mprof_GC() {
+       for b := mbuckets; b != nil; b = b.allnext {
+               mp := b.mp()
+               mp.allocs += mp.prev_allocs
+               mp.frees += mp.prev_frees
+               mp.alloc_bytes += mp.prev_alloc_bytes
+               mp.free_bytes += mp.prev_free_bytes
+
+               mp.prev_allocs = mp.recent_allocs
+               mp.prev_frees = mp.recent_frees
+               mp.prev_alloc_bytes = mp.recent_alloc_bytes
+               mp.prev_free_bytes = mp.recent_free_bytes
+
+               mp.recent_allocs = 0
+               mp.recent_frees = 0
+               mp.recent_alloc_bytes = 0
+               mp.recent_free_bytes = 0
+       }
+}
+
+// Record that a gc just happened: all the 'recent' statistics are now real.
+func mProf_GC() {
+       lock(&proflock)
+       mprof_GC()
+       unlock(&proflock)
+}
+
+// Called by malloc to record a profiled block.
+func mProf_Malloc(p unsafe.Pointer, size uintptr) {
+       var stk [maxStack]location
+       nstk := callers(4, stk[:])
+       lock(&proflock)
+       b := stkbucket(memProfile, size, stk[:nstk], true)
+       mp := b.mp()
+       mp.recent_allocs++
+       mp.recent_alloc_bytes += size
+       unlock(&proflock)
+
+       // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
+       // This reduces potential contention and chances of deadlocks.
+       // Since the object must be alive during call to mProf_Malloc,
+       // it's fine to do this non-atomically.
+       systemstack(func() {
+               setprofilebucket(p, b)
+       })
+}
+
+// Called when freeing a profiled block.
+func mProf_Free(b *bucket, size uintptr) {
+       lock(&proflock)
+       mp := b.mp()
+       mp.prev_frees++
+       mp.prev_free_bytes += size
+       unlock(&proflock)
+}
+
+var blockprofilerate uint64 // in CPU ticks
+
+// SetBlockProfileRate controls the fraction of goroutine blocking events
+// that are reported in the blocking profile. The profiler aims to sample
+// an average of one blocking event per rate nanoseconds spent blocked.
+//
+// To include every blocking event in the profile, pass rate = 1.
+// To turn off profiling entirely, pass rate <= 0.
+func SetBlockProfileRate(rate int) {
+       var r int64
+       if rate <= 0 {
+               r = 0 // disable profiling
+       } else if rate == 1 {
+               r = 1 // profile everything
+       } else {
+               // convert ns to cycles, use float64 to prevent overflow during multiplication
+               r = int64(float64(rate) * float64(tickspersecond()) / (1000 * 1000 * 1000))
+               if r == 0 {
+                       r = 1
+               }
+       }
+
+       atomic.Store64(&blockprofilerate, uint64(r))
+}
+
+func blockevent(cycles int64, skip int) {
+       if cycles <= 0 {
+               cycles = 1
+       }
+       rate := int64(atomic.Load64(&blockprofilerate))
+       if rate <= 0 || (rate > cycles && int64(fastrand1())%rate > cycles) {
+               return
+       }
+       gp := getg()
+       var nstk int
+       var stk [maxStack]location
+       if gp.m.curg == nil || gp.m.curg == gp {
+               nstk = callers(skip, stk[:])
+       } else {
+               // FIXME: This should get a traceback of gp.m.curg.
+               // nstk = gcallers(gp.m.curg, skip, stk[:])
+               nstk = callers(skip, stk[:])
+       }
+       lock(&proflock)
+       b := stkbucket(blockProfile, 0, stk[:nstk], true)
+       b.bp().count++
+       b.bp().cycles += cycles
+       unlock(&proflock)
+}
+
+// Go interface to profile data.
+
+// A StackRecord describes a single execution stack.
+type StackRecord struct {
+       Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *StackRecord) Stack() []uintptr {
+       for i, v := range r.Stack0 {
+               if v == 0 {
+                       return r.Stack0[0:i]
+               }
+       }
+       return r.Stack0[0:]
+}
+
+// MemProfileRate controls the fraction of memory allocations
+// that are recorded and reported in the memory profile.
+// The profiler aims to sample an average of
+// one allocation per MemProfileRate bytes allocated.
+//
+// To include every allocated block in the profile, set MemProfileRate to 1.
+// To turn off profiling entirely, set MemProfileRate to 0.
+//
+// The tools that process the memory profiles assume that the
+// profile rate is constant across the lifetime of the program
+// and equal to the current value. Programs that change the
+// memory profiling rate should do so just once, as early as
+// possible in the execution of the program (for example,
+// at the beginning of main).
+var MemProfileRate int = 512 * 1024
+
+// A MemProfileRecord describes the live objects allocated
+// by a particular call sequence (stack trace).
+type MemProfileRecord struct {
+       AllocBytes, FreeBytes     int64       // number of bytes allocated, freed
+       AllocObjects, FreeObjects int64       // number of objects allocated, freed
+       Stack0                    [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
+func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
+
+// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
+func (r *MemProfileRecord) InUseObjects() int64 {
+       return r.AllocObjects - r.FreeObjects
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *MemProfileRecord) Stack() []uintptr {
+       for i, v := range r.Stack0 {
+               if v == 0 {
+                       return r.Stack0[0:i]
+               }
+       }
+       return r.Stack0[0:]
+}
+
+// MemProfile returns a profile of memory allocated and freed per allocation
+// site.
+//
+// MemProfile returns n, the number of records in the current memory profile.
+// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
+// If len(p) < n, MemProfile does not change p and returns n, false.
+//
+// If inuseZero is true, the profile includes allocation records
+// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
+// These are sites where memory was allocated, but it has all
+// been released back to the runtime.
+//
+// The returned profile may be up to two garbage collection cycles old.
+// This is to avoid skewing the profile toward allocations; because
+// allocations happen in real time but frees are delayed until the garbage
+// collector performs sweeping, the profile only accounts for allocations
+// that have had a chance to be freed by the garbage collector.
+//
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.memprofile flag instead
+// of calling MemProfile directly.
+func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
+       lock(&proflock)
+       clear := true
+       for b := mbuckets; b != nil; b = b.allnext {
+               mp := b.mp()
+               if inuseZero || mp.alloc_bytes != mp.free_bytes {
+                       n++
+               }
+               if mp.allocs != 0 || mp.frees != 0 {
+                       clear = false
+               }
+       }
+       if clear {
+               // Absolutely no data, suggesting that a garbage collection
+               // has not yet happened. In order to allow profiling when
+               // garbage collection is disabled from the beginning of execution,
+               // accumulate stats as if a GC just happened, and recount buckets.
+               mprof_GC()
+               mprof_GC()
+               n = 0
+               for b := mbuckets; b != nil; b = b.allnext {
+                       mp := b.mp()
+                       if inuseZero || mp.alloc_bytes != mp.free_bytes {
+                               n++
+                       }
+               }
+       }
+       if n <= len(p) {
+               ok = true
+               idx := 0
+               for b := mbuckets; b != nil; b = b.allnext {
+                       mp := b.mp()
+                       if inuseZero || mp.alloc_bytes != mp.free_bytes {
+                               record(&p[idx], b)
+                               idx++
+                       }
+               }
+       }
+       unlock(&proflock)
+       return
+}
+
+// Write b's data to r.
+func record(r *MemProfileRecord, b *bucket) {
+       mp := b.mp()
+       r.AllocBytes = int64(mp.alloc_bytes)
+       r.FreeBytes = int64(mp.free_bytes)
+       r.AllocObjects = int64(mp.allocs)
+       r.FreeObjects = int64(mp.frees)
+       for i, loc := range b.stk() {
+               if i >= len(r.Stack0) {
+                       break
+               }
+               r.Stack0[i] = loc.pc
+       }
+       for i := int(b.nstk); i < len(r.Stack0); i++ {
+               r.Stack0[i] = 0
+       }
+}
+
+func iterate_memprof(fn func(*bucket, uintptr, *location, uintptr, uintptr, uintptr)) {
+       lock(&proflock)
+       for b := mbuckets; b != nil; b = b.allnext {
+               mp := b.mp()
+               fn(b, b.nstk, &b.stk()[0], b.size, mp.allocs, mp.frees)
+       }
+       unlock(&proflock)
+}
+
+// BlockProfileRecord describes blocking events originated
+// at a particular call sequence (stack trace).
+type BlockProfileRecord struct {
+       Count  int64
+       Cycles int64
+       StackRecord
+}
+
+// BlockProfile returns n, the number of records in the current blocking profile.
+// If len(p) >= n, BlockProfile copies the profile into p and returns n, true.
+// If len(p) < n, BlockProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.blockprofile flag instead
+// of calling BlockProfile directly.
+func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
+       lock(&proflock)
+       for b := bbuckets; b != nil; b = b.allnext {
+               n++
+       }
+       if n <= len(p) {
+               ok = true
+               for b := bbuckets; b != nil; b = b.allnext {
+                       bp := b.bp()
+                       r := &p[0]
+                       r.Count = bp.count
+                       r.Cycles = bp.cycles
+                       i := 0
+                       var loc location
+                       for i, loc = range b.stk() {
+                               if i >= len(r.Stack0) {
+                                       break
+                               }
+                               r.Stack0[i] = loc.pc
+                       }
+                       for ; i < len(r.Stack0); i++ {
+                               r.Stack0[i] = 0
+                       }
+                       p = p[1:]
+               }
+       }
+       unlock(&proflock)
+       return
+}
+
+// ThreadCreateProfile returns n, the number of records in the thread creation profile.
+// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true.
+// If len(p) < n, ThreadCreateProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling ThreadCreateProfile directly.
+func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
+       first := (*m)(atomic.Loadp(unsafe.Pointer(allm())))
+       for mp := first; mp != nil; mp = mp.alllink {
+               n++
+       }
+       if n <= len(p) {
+               ok = true
+               i := 0
+               for mp := first; mp != nil; mp = mp.alllink {
+                       for j := range mp.createstack {
+                               p[i].Stack0[j] = mp.createstack[j].pc
+                       }
+                       i++
+               }
+       }
+       return
+}
+
+// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
+// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
+// If len(p) < n, GoroutineProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling GoroutineProfile directly.
+func GoroutineProfile(p []StackRecord) (n int, ok bool) {
+       gp := getg()
+
+       isOK := func(gp1 *g) bool {
+               // Checking isSystemGoroutine here makes GoroutineProfile
+               // consistent with both NumGoroutine and Stack.
+               return gp1 != gp && readgstatus(gp1) != _Gdead && !isSystemGoroutine(gp1)
+       }
+
+       stopTheWorld("profile")
+
+       n = 1
+       for _, gp1 := range allgs() {
+               if isOK(gp1) {
+                       n++
+               }
+       }
+
+       if n <= len(p) {
+               ok = true
+               r := p
+
+               // Save current goroutine.
+               saveg(gp, &r[0])
+               r = r[1:]
+
+               // Save other goroutines.
+               for _, gp1 := range allgs() {
+                       if isOK(gp1) {
+                               if len(r) == 0 {
+                                       // Should be impossible, but better to return a
+                                       // truncated profile than to crash the entire process.
+                                       break
+                               }
+                               saveg(gp1, &r[0])
+                               r = r[1:]
+                       }
+               }
+       }
+
+       startTheWorld()
+
+       return n, ok
+}
+
+func saveg(gp *g, r *StackRecord) {
+       if gp == getg() {
+               var locbuf [32]location
+               n := callers(1, locbuf[:])
+               for i := 0; i < n; i++ {
+                       r.Stack0[i] = locbuf[i].pc
+               }
+               if n < len(r.Stack0) {
+                       r.Stack0[n] = 0
+               }
+       } else {
+               // FIXME: Not implemented.
+               r.Stack0[0] = 0
+       }
+}
+
+// Stack formats a stack trace of the calling goroutine into buf
+// and returns the number of bytes written to buf.
+// If all is true, Stack formats stack traces of all other goroutines
+// into buf after the trace for the current goroutine.
+func Stack(buf []byte, all bool) int {
+       if all {
+               stopTheWorld("stack trace")
+       }
+
+       n := 0
+       if len(buf) > 0 {
+               gp := getg()
+               // Force traceback=1 to override GOTRACEBACK setting,
+               // so that Stack's results are consistent.
+               // GOTRACEBACK is only about crash dumps.
+               gp.m.traceback = 1
+               gp.writebuf = buf[0:0:len(buf)]
+               goroutineheader(gp)
+               traceback()
+               if all {
+                       tracebackothers(gp)
+               }
+               gp.m.traceback = 0
+               n = len(gp.writebuf)
+               gp.writebuf = nil
+       }
+
+       if all {
+               startTheWorld()
+       }
+       return n
+}
+
+// Tracing of alloc/free/gc.
+
+var tracelock mutex
+
+func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
+       lock(&tracelock)
+       gp := getg()
+       gp.m.traceback = 2
+       if typ == nil {
+               print("tracealloc(", p, ", ", hex(size), ")\n")
+       } else {
+               print("tracealloc(", p, ", ", hex(size), ", ", *typ.string, ")\n")
+       }
+       if gp.m.curg == nil || gp == gp.m.curg {
+               goroutineheader(gp)
+               traceback()
+       } else {
+               goroutineheader(gp.m.curg)
+               // FIXME: Can't do traceback of other g.
+       }
+       print("\n")
+       gp.m.traceback = 0
+       unlock(&tracelock)
+}
+
+func tracefree(p unsafe.Pointer, size uintptr) {
+       lock(&tracelock)
+       gp := getg()
+       gp.m.traceback = 2
+       print("tracefree(", p, ", ", hex(size), ")\n")
+       goroutineheader(gp)
+       traceback()
+       print("\n")
+       gp.m.traceback = 0
+       unlock(&tracelock)
+}
+
+func tracegc() {
+       lock(&tracelock)
+       gp := getg()
+       gp.m.traceback = 2
+       print("tracegc()\n")
+       // running on m->g0 stack; show all non-g0 goroutines
+       tracebackothers(gp)
+       print("end tracegc\n")
+       print("\n")
+       gp.m.traceback = 0
+       unlock(&tracelock)
+}
index 25b5b79de20a650ae59dd90870b0b7ae45c785d8..660d81e47f344b0d0300ebb84c0efa9c9287d4a9 100644 (file)
@@ -394,7 +394,7 @@ type g struct {
        issystem     bool // do not output in stack dump
        isbackground bool // ignore in deadlock detector
 
-       traceback *traceback // stack traceback buffer
+       traceback *tracebackg // stack traceback buffer
 
        context      g_ucontext_t       // saved context for setcontext
        stackcontext [10]unsafe.Pointer // split-stack context
@@ -801,21 +801,6 @@ var (
 // array.
 type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
 
-// traceback is used to collect stack traces from other goroutines.
-type traceback struct {
-       gp     *g
-       locbuf [_TracebackMaxFrames]location
-       c      int
-}
-
-// location is a location in the program, used for backtraces.
-type location struct {
-       pc       uintptr
-       filename string
-       function string
-       lineno   int
-}
-
 // cgoMal tracks allocations made by _cgo_allocate
 // FIXME: _cgo_allocate has been removed from gc and can probably be
 // removed from gccgo too.
index 30a0f559a929f98d64796943baa9295338ef3c04..e1c28fac5432d69f76fb47e21db9488a71e33185 100644 (file)
@@ -307,11 +307,6 @@ func gopark(func(*g, unsafe.Pointer) bool, unsafe.Pointer, string, byte, int)
 func goparkunlock(*mutex, string, byte, int)
 func goready(*g, int)
 
-// Temporary for gccgo until we port mprof.go.
-var blockprofilerate uint64
-
-func blockevent(cycles int64, skip int) {}
-
 // Temporary hack for gccgo until we port proc.go.
 //go:nosplit
 func acquireSudog() *sudog {
@@ -428,3 +423,24 @@ func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer
 func cpuprofAdd(stk []uintptr) {
        cpuprof.add(stk)
 }
+
+// For gccgo until we port proc.go.
+func Breakpoint()
+func LockOSThread()
+func UnlockOSThread()
+func allm() *m
+func allgs() []*g
+
+//go:nosplit
+func readgstatus(gp *g) uint32 {
+       return atomic.Load(&gp.atomicstatus)
+}
+
+// Temporary for gccgo until we port malloc.go
+func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer
+
+// Temporary for gccgo until we port mheap.go
+func setprofilebucket(p unsafe.Pointer, b *bucket)
+
+// Currently in proc.c.
+func tracebackothers(*g)
diff --git a/libgo/go/runtime/traceback_gccgo.go b/libgo/go/runtime/traceback_gccgo.go
new file mode 100644 (file)
index 0000000..4f3d7c0
--- /dev/null
@@ -0,0 +1,164 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Traceback support for gccgo.
+// The actual traceback code is written in C.
+
+package runtime
+
+import (
+       "runtime/internal/sys"
+       _ "unsafe" // for go:linkname
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+// These are temporary for C runtime code to call.
+//go:linkname traceback runtime.traceback
+//go:linkname printtrace runtime.printtrace
+//go:linkname goroutineheader runtime.goroutineheader
+//go:linkname printcreatedby runtime.printcreatedby
+
+func printcreatedby(gp *g) {
+       // Show what created goroutine, except main goroutine (goid 1).
+       pc := gp.gopc
+       tracepc := pc // back up to CALL instruction for funcfileline.
+       entry := funcentry(tracepc)
+       if entry != 0 && tracepc > entry {
+               tracepc -= sys.PCQuantum
+       }
+       function, file, line := funcfileline(tracepc, -1)
+       if function != "" && showframe(function, gp) && gp.goid != 1 {
+               print("created by ", function, "\n")
+               print("\t", file, ":", line)
+               if entry != 0 && pc > entry {
+                       print(" +", hex(pc-entry))
+               }
+               print("\n")
+       }
+}
+
+// tracebackg is used to collect stack traces from other goroutines.
+type tracebackg struct {
+       gp     *g
+       locbuf [_TracebackMaxFrames]location
+       c      int
+}
+
+// location is a location in the program, used for backtraces.
+type location struct {
+       pc       uintptr
+       filename string
+       function string
+       lineno   int
+}
+
+//extern runtime_callers
+func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32
+
+// callers returns a stack trace of the current goroutine.
+// The gc version of callers takes []uintptr, but we take []location.
+func callers(skip int, locbuf []location) int {
+       n := c_callers(int32(skip), &locbuf[0], int32(len(locbuf)), false)
+       return int(n)
+}
+
+// traceback prints a traceback of the current goroutine.
+// This differs from the gc version, which is given pc, sp, lr and g and
+// can print a traceback of any goroutine.
+func traceback() {
+       var locbuf [100]location
+       c := c_callers(1, &locbuf[0], int32(len(locbuf)), false)
+       printtrace(locbuf[:c], getg())
+}
+
+// printtrace prints a traceback from locbuf.
+func printtrace(locbuf []location, gp *g) {
+       for i := range locbuf {
+               if showframe(locbuf[i].function, gp) {
+                       print(locbuf[i].function, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno)
+               }
+       }
+}
+
+// showframe returns whether to print a frame in a traceback.
+// name is the function name.
+func showframe(name string, gp *g) bool {
+       g := getg()
+       if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
+               return true
+       }
+       level, _, _ := gotraceback()
+
+       // Special case: always show runtime.gopanic frame, so that we can
+       // see where a panic started in the middle of a stack trace.
+       // See golang.org/issue/5832.
+       // __go_panic is the current gccgo name.
+       if name == "runtime.gopanic" || name == "__go_panic" {
+               return true
+       }
+
+       return level > 1 || contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
+}
+
+// isExportedRuntime reports whether name is an exported runtime function.
+// It is only for runtime functions, so ASCII A-Z is fine.
+func isExportedRuntime(name string) bool {
+       const n = len("runtime.")
+       return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
+}
+
+var gStatusStrings = [...]string{
+       _Gidle:      "idle",
+       _Grunnable:  "runnable",
+       _Grunning:   "running",
+       _Gsyscall:   "syscall",
+       _Gwaiting:   "waiting",
+       _Gdead:      "dead",
+       _Gcopystack: "copystack",
+}
+
+func goroutineheader(gp *g) {
+       gpstatus := readgstatus(gp)
+
+       isScan := gpstatus&_Gscan != 0
+       gpstatus &^= _Gscan // drop the scan bit
+
+       // Basic string status
+       var status string
+       if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
+               status = gStatusStrings[gpstatus]
+       } else {
+               status = "???"
+       }
+
+       // Override.
+       if gpstatus == _Gwaiting && gp.waitreason != "" {
+               status = gp.waitreason
+       }
+
+       // approx time the G is blocked, in minutes
+       var waitfor int64
+       if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
+               waitfor = (nanotime() - gp.waitsince) / 60e9
+       }
+       print("goroutine ", gp.goid, " [", status)
+       if isScan {
+               print(" (scan)")
+       }
+       if waitfor >= 1 {
+               print(", ", waitfor, " minutes")
+       }
+       if gp.lockedm != nil {
+               print(", locked to thread")
+       }
+       print("]:\n")
+}
+
+// isSystemGoroutine reports whether the goroutine g must be omitted in
+// stack dumps and deadlock detector.
+func isSystemGoroutine(gp *g) bool {
+       // FIXME.
+       return false
+}
diff --git a/libgo/runtime/go-traceback.c b/libgo/runtime/go-traceback.c
deleted file mode 100644 (file)
index 7b33cca..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* go-traceback.c -- stack backtrace for Go.
-
-   Copyright 2012 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include "config.h"
-
-#include "runtime.h"
-
-/* Print a stack trace for the current goroutine.  */
-
-void
-runtime_traceback ()
-{
-  Location locbuf[100];
-  int32 c;
-
-  c = runtime_callers (1, locbuf, nelem (locbuf), false);
-  runtime_printtrace (locbuf, c, true);
-}
-
-void
-runtime_printtrace (Location *locbuf, int32 c, bool current)
-{
-  int32 i;
-
-  for (i = 0; i < c; ++i)
-    {
-      if (runtime_showframe (locbuf[i].function, current))
-       {
-         runtime_printf ("%S\n", locbuf[i].function);
-         runtime_printf ("\t%S:%D\n", locbuf[i].filename,
-                         (int64) locbuf[i].lineno);
-       }
-    }
-}
index 12a25b57677707a65abd064e0a5bfff63726563f..011eaa91d0705a99748987d9f6595cdcab9a9d01 100644 (file)
@@ -303,7 +303,7 @@ struct SpecialFinalizer
 };
 
 // The described object is being heap profiled.
-typedef struct Bucket Bucket; // from mprof.goc
+typedef struct bucket Bucket; // from mprof.go
 typedef struct SpecialProfile SpecialProfile;
 struct SpecialProfile
 {
@@ -414,7 +414,8 @@ void        runtime_MHeap_Scavenger(void*);
 void   runtime_MHeap_SplitSpan(MHeap *h, MSpan *s);
 
 void*  runtime_mallocgc(uintptr size, uintptr typ, uint32 flag);
-void*  runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat);
+void*  runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
+  __asm__(GOSYM_PREFIX "runtime.persistentalloc");
 int32  runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **s);
 void   runtime_gc(int32 force);
 uintptr        runtime_sweepone(void);
@@ -428,12 +429,15 @@ void      runtime_markspan(void *v, uintptr size, uintptr n, bool leftover);
 void   runtime_unmarkspan(void *v, uintptr size);
 void   runtime_purgecachedstats(MCache*);
 void*  runtime_cnew(const Type*)
-         __asm__(GOSYM_PREFIX "runtime.newobject");
+  __asm__(GOSYM_PREFIX "runtime.newobject");
 void*  runtime_cnewarray(const Type*, intgo)
-         __asm__(GOSYM_PREFIX "runtime.newarray");
-void   runtime_tracealloc(void*, uintptr, uintptr);
-void   runtime_tracefree(void*, uintptr);
-void   runtime_tracegc(void);
+  __asm__(GOSYM_PREFIX "runtime.newarray");
+void   runtime_tracealloc(void*, uintptr, uintptr)
+  __asm__ (GOSYM_PREFIX "runtime.tracealloc");
+void   runtime_tracefree(void*, uintptr)
+  __asm__ (GOSYM_PREFIX "runtime.tracefree");
+void   runtime_tracegc(void)
+  __asm__ (GOSYM_PREFIX "runtime.tracegc");
 
 uintptr        runtime_gettype(void*);
 
@@ -455,10 +459,14 @@ struct Obj
        uintptr ti;     // type info
 };
 
-void   runtime_MProf_Malloc(void*, uintptr);
-void   runtime_MProf_Free(Bucket*, uintptr, bool);
-void   runtime_MProf_GC(void);
-void   runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr));
+void   runtime_MProf_Malloc(void*, uintptr)
+  __asm__ (GOSYM_PREFIX "runtime.mProf_Malloc");
+void   runtime_MProf_Free(Bucket*, uintptr, bool)
+  __asm__ (GOSYM_PREFIX "runtime.mProf_Free");
+void   runtime_MProf_GC(void)
+  __asm__ (GOSYM_PREFIX "runtime.mProf_GC");
+void   runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr))
+  __asm__ (GOSYM_PREFIX "runtime.iterate_memprof");
 int32  runtime_gcprocs(void);
 void   runtime_helpgc(int32 nproc);
 void   runtime_gchelper(void);
@@ -467,7 +475,8 @@ G*  runtime_wakefing(void);
 extern bool    runtime_fingwait;
 extern bool    runtime_fingwake;
 
-void   runtime_setprofilebucket(void *p, Bucket *b);
+void   runtime_setprofilebucket(void *p, Bucket *b)
+  __asm__ (GOSYM_PREFIX "runtime.setprofilebucket");
 
 struct __go_func_type;
 struct __go_ptr_type;
@@ -533,7 +542,6 @@ int32       runtime_setgcpercent(int32);
 #define PoisonStack ((uintptr)0x6868686868686868ULL)
 
 struct Workbuf;
-void   runtime_MProf_Mark(struct Workbuf**, void (*)(struct Workbuf**, Obj));
 void   runtime_proc_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
 void   runtime_time_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
 void   runtime_netpoll_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
index 487767878282a6687b058ea7d7a18d340c5e4c04..2c8e5a8e643c97bbdb6b7a290329781f3542d325 100644 (file)
@@ -1277,7 +1277,6 @@ markroot(ParFor *desc, uint32 i)
                enqueue1(&wbuf, (Obj){(byte*)&runtime_allp, sizeof runtime_allp, 0});
                enqueue1(&wbuf, (Obj){(byte*)&work, sizeof work, 0});
                runtime_proc_scan(&wbuf, enqueue1);
-               runtime_MProf_Mark(&wbuf, enqueue1);
                runtime_time_scan(&wbuf, enqueue1);
                runtime_netpoll_scan(&wbuf, enqueue1);
                break;
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
deleted file mode 100644 (file)
index c4966a4..0000000
+++ /dev/null
@@ -1,564 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Malloc profiling.
-// Patterned after tcmalloc's algorithms; shorter code.
-
-package runtime
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "defs.h"
-#include "go-type.h"
-#include "go-string.h"
-
-// NOTE(rsc): Everything here could use cas if contention became an issue.
-static Lock proflock;
-
-// All memory allocations are local and do not escape outside of the profiler.
-// The profiler is forbidden from referring to garbage-collected memory.
-
-enum { MProf, BProf };  // profile types
-
-// Per-call-stack profiling information.
-// Lookup by hashing call stack into a linked-list hash table.
-struct Bucket
-{
-       Bucket  *next;  // next in hash list
-       Bucket  *allnext;       // next in list of all mbuckets/bbuckets
-       int32   typ;
-       // Generally unions can break precise GC,
-       // this one is fine because it does not contain pointers.
-       union
-       {
-               struct  // typ == MProf
-               {
-                       // The following complex 3-stage scheme of stats accumulation
-                       // is required to obtain a consistent picture of mallocs and frees
-                       // for some point in time.
-                       // The problem is that mallocs come in real time, while frees
-                       // come only after a GC during concurrent sweeping. So if we would
-                       // naively count them, we would get a skew toward mallocs.
-                       //
-                       // Mallocs are accounted in recent stats.
-                       // Explicit frees are accounted in recent stats.
-                       // GC frees are accounted in prev stats.
-                       // After GC prev stats are added to final stats and
-                       // recent stats are moved into prev stats.
-                       uintptr allocs;
-                       uintptr frees;
-                       uintptr alloc_bytes;
-                       uintptr free_bytes;
-
-                       uintptr prev_allocs;  // since last but one till last gc
-                       uintptr prev_frees;
-                       uintptr prev_alloc_bytes;
-                       uintptr prev_free_bytes;
-
-                       uintptr recent_allocs;  // since last gc till now
-                       uintptr recent_frees;
-                       uintptr recent_alloc_bytes;
-                       uintptr recent_free_bytes;
-
-               };
-               struct  // typ == BProf
-               {
-                       int64   count;
-                       int64   cycles;
-               };
-       };
-       uintptr hash;   // hash of size + stk
-       uintptr size;
-       uintptr nstk;
-       Location stk[1];
-};
-enum {
-       BuckHashSize = 179999,
-};
-static Bucket **buckhash;
-static Bucket *mbuckets;  // memory profile buckets
-static Bucket *bbuckets;  // blocking profile buckets
-static uintptr bucketmem;
-
-// Return the bucket for stk[0:nstk], allocating new bucket if needed.
-static Bucket*
-stkbucket(int32 typ, uintptr size, Location *stk, int32 nstk, bool alloc)
-{
-       int32 i, j;
-       uintptr h;
-       Bucket *b;
-
-       if(buckhash == nil) {
-               buckhash = runtime_SysAlloc(BuckHashSize*sizeof buckhash[0], &mstats()->buckhash_sys);
-               if(buckhash == nil)
-                       runtime_throw("runtime: cannot allocate memory");
-       }
-
-       // Hash stack.
-       h = 0;
-       for(i=0; i<nstk; i++) {
-               h += stk[i].pc;
-               h += h<<10;
-               h ^= h>>6;
-       }
-       // hash in size
-       h += size;
-       h += h<<10;
-       h ^= h>>6;
-       // finalize
-       h += h<<3;
-       h ^= h>>11;
-
-       i = h%BuckHashSize;
-       for(b = buckhash[i]; b; b=b->next) {
-               if(b->typ == typ && b->hash == h && b->size == size && b->nstk == (uintptr)nstk) {
-                       for(j = 0; j < nstk; j++) {
-                               if(b->stk[j].pc != stk[j].pc ||
-                                  b->stk[j].lineno != stk[j].lineno ||
-                                  !__go_strings_equal(b->stk[j].filename, stk[j].filename))
-                                       break;
-                       }
-                       if (j == nstk)
-                               return b;
-               }
-       }
-
-       if(!alloc)
-               return nil;
-
-       b = runtime_persistentalloc(sizeof *b + nstk*sizeof stk[0], 0, &mstats()->buckhash_sys);
-       bucketmem += sizeof *b + nstk*sizeof stk[0];
-       runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
-       b->typ = typ;
-       b->hash = h;
-       b->size = size;
-       b->nstk = nstk;
-       b->next = buckhash[i];
-       buckhash[i] = b;
-       if(typ == MProf) {
-               b->allnext = mbuckets;
-               mbuckets = b;
-       } else {
-               b->allnext = bbuckets;
-               bbuckets = b;
-       }
-       return b;
-}
-
-static void
-MProf_GC(void)
-{
-       Bucket *b;
-
-       for(b=mbuckets; b; b=b->allnext) {
-               b->allocs += b->prev_allocs;
-               b->frees += b->prev_frees;
-               b->alloc_bytes += b->prev_alloc_bytes;
-               b->free_bytes += b->prev_free_bytes;
-
-               b->prev_allocs = b->recent_allocs;
-               b->prev_frees = b->recent_frees;
-               b->prev_alloc_bytes = b->recent_alloc_bytes;
-               b->prev_free_bytes = b->recent_free_bytes;
-
-               b->recent_allocs = 0;
-               b->recent_frees = 0;
-               b->recent_alloc_bytes = 0;
-               b->recent_free_bytes = 0;
-       }
-}
-
-// Record that a gc just happened: all the 'recent' statistics are now real.
-void
-runtime_MProf_GC(void)
-{
-       runtime_lock(&proflock);
-       MProf_GC();
-       runtime_unlock(&proflock);
-}
-
-// Called by malloc to record a profiled block.
-void
-runtime_MProf_Malloc(void *p, uintptr size)
-{
-       Location stk[32];
-       Bucket *b;
-       int32 nstk;
-
-       nstk = runtime_callers(1, stk, nelem(stk), false);
-       runtime_lock(&proflock);
-       b = stkbucket(MProf, size, stk, nstk, true);
-       b->recent_allocs++;
-       b->recent_alloc_bytes += size;
-       runtime_unlock(&proflock);
-
-       // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
-       // This reduces potential contention and chances of deadlocks.
-       // Since the object must be alive during call to MProf_Malloc,
-       // it's fine to do this non-atomically.
-       runtime_setprofilebucket(p, b);
-}
-
-// Called when freeing a profiled block.
-void
-runtime_MProf_Free(Bucket *b, uintptr size, bool freed)
-{
-       runtime_lock(&proflock);
-       if(freed) {
-               b->recent_frees++;
-               b->recent_free_bytes += size;
-       } else {
-               b->prev_frees++;
-               b->prev_free_bytes += size;
-       }
-       runtime_unlock(&proflock);
-}
-
-int64 runtime_blockprofilerate;  // in CPU ticks
-
-void runtime_SetBlockProfileRate(intgo) __asm__ (GOSYM_PREFIX "runtime.SetBlockProfileRate");
-
-void
-runtime_SetBlockProfileRate(intgo rate)
-{
-       int64 r;
-
-       if(rate <= 0)
-               r = 0;  // disable profiling
-       else {
-               // convert ns to cycles, use float64 to prevent overflow during multiplication
-               r = (float64)rate*runtime_tickspersecond()/(1000*1000*1000);
-               if(r == 0)
-                       r = 1;
-       }
-       runtime_atomicstore64((uint64*)&runtime_blockprofilerate, r);
-}
-
-void
-runtime_blockevent(int64 cycles, int32 skip)
-{
-       int32 nstk;
-       int64 rate;
-       Location stk[32];
-       Bucket *b;
-
-       if(cycles <= 0)
-               return;
-       rate = runtime_atomicload64((uint64*)&runtime_blockprofilerate);
-       if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
-               return;
-
-       nstk = runtime_callers(skip, stk, nelem(stk), false);
-       runtime_lock(&proflock);
-       b = stkbucket(BProf, 0, stk, nstk, true);
-       b->count++;
-       b->cycles += cycles;
-       runtime_unlock(&proflock);
-}
-
-// Go interface to profile data.  (Declared in debug.go)
-
-// Must match MemProfileRecord in debug.go.
-typedef struct Record Record;
-struct Record {
-       int64 alloc_bytes, free_bytes;
-       int64 alloc_objects, free_objects;
-       uintptr stk[32];
-};
-
-// Write b's data to r.
-static void
-record(Record *r, Bucket *b)
-{
-       uint32 i;
-
-       r->alloc_bytes = b->alloc_bytes;
-       r->free_bytes = b->free_bytes;
-       r->alloc_objects = b->allocs;
-       r->free_objects = b->frees;
-       for(i=0; i<b->nstk && i<nelem(r->stk); i++)
-               r->stk[i] = b->stk[i].pc;
-       for(; i<nelem(r->stk); i++)
-               r->stk[i] = 0;
-}
-
-func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
-       Bucket *b;
-       Record *r;
-       bool clear;
-
-       runtime_lock(&proflock);
-       n = 0;
-       clear = true;
-       for(b=mbuckets; b; b=b->allnext) {
-               if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
-                       n++;
-               if(b->allocs != 0 || b->frees != 0)
-                       clear = false;
-       }
-       if(clear) {
-               // Absolutely no data, suggesting that a garbage collection
-               // has not yet happened. In order to allow profiling when
-               // garbage collection is disabled from the beginning of execution,
-               // accumulate stats as if a GC just happened, and recount buckets.
-               MProf_GC();
-               MProf_GC();
-               n = 0;
-               for(b=mbuckets; b; b=b->allnext)
-                       if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
-                               n++;
-       }
-       ok = false;
-       if(n <= p.__count) {
-               ok = true;
-               r = (Record*)p.__values;
-               for(b=mbuckets; b; b=b->allnext)
-                       if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
-                               record(r++, b);
-       }
-       runtime_unlock(&proflock);
-}
-
-void
-runtime_MProf_Mark(struct Workbuf **wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
-       // buckhash is not allocated via mallocgc.
-       enqueue1(wbufp, (Obj){(byte*)&mbuckets, sizeof mbuckets, 0});
-       enqueue1(wbufp, (Obj){(byte*)&bbuckets, sizeof bbuckets, 0});
-}
-
-void
-runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr))
-{
-       Bucket *b;
-
-       runtime_lock(&proflock);
-       for(b=mbuckets; b; b=b->allnext) {
-               callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees);
-       }
-       runtime_unlock(&proflock);
-}
-
-// Must match BlockProfileRecord in debug.go.
-typedef struct BRecord BRecord;
-struct BRecord {
-       int64 count;
-       int64 cycles;
-       uintptr stk[32];
-};
-
-func BlockProfile(p Slice) (n int, ok bool) {
-       Bucket *b;
-       BRecord *r;
-       int32 i;
-
-       runtime_lock(&proflock);
-       n = 0;
-       for(b=bbuckets; b; b=b->allnext)
-               n++;
-       ok = false;
-       if(n <= p.__count) {
-               ok = true;
-               r = (BRecord*)p.__values;
-               for(b=bbuckets; b; b=b->allnext, r++) {
-                       r->count = b->count;
-                       r->cycles = b->cycles;
-                       for(i=0; (uintptr)i<b->nstk && (uintptr)i<nelem(r->stk); i++)
-                               r->stk[i] = b->stk[i].pc;
-                       for(; (uintptr)i<nelem(r->stk); i++)
-                               r->stk[i] = 0;                  
-               }
-       }
-       runtime_unlock(&proflock);
-}
-
-// Must match StackRecord in debug.go.
-typedef struct TRecord TRecord;
-struct TRecord {
-       uintptr stk[32];
-};
-
-func ThreadCreateProfile(p Slice) (n int, ok bool) {
-       TRecord *r;
-       M *first, *mp;
-       int32 i;
-       
-       first = runtime_atomicloadp(&runtime_allm);
-       n = 0;
-       for(mp=first; mp; mp=mp->alllink)
-               n++;
-       ok = false;
-       if(n <= p.__count) {
-               ok = true;
-               r = (TRecord*)p.__values;
-               for(mp=first; mp; mp=mp->alllink) {
-                       for(i = 0; (uintptr)i < nelem(r->stk); i++) {
-                               r->stk[i] = mp->createstack[i].pc;
-                       }
-                       r++;
-               }
-       }
-}
-
-func Stack(b Slice, all bool) (n int) {
-       byte *pc;
-       bool enablegc = false;
-       
-       pc = (byte*)(uintptr)runtime_getcallerpc(&b);
-
-       if(all) {
-               runtime_acquireWorldsema();
-               runtime_m()->gcing = 1;
-               runtime_stopTheWorldWithSema();
-               enablegc = mstats()->enablegc;
-               mstats()->enablegc = false;
-       }
-
-       if(b.__count == 0)
-               n = 0;
-       else{
-               G* g = runtime_g();
-               g->writebuf.__values = b.__values;
-               g->writebuf.__count = 0;
-               g->writebuf.__capacity = b.__count;
-               USED(pc);
-               runtime_goroutineheader(g);
-               runtime_traceback();
-               runtime_printcreatedby(g);
-               if(all)
-                       runtime_tracebackothers(g);
-               n = g->writebuf.__count;
-               g->writebuf.__values = nil;
-               g->writebuf.__count = 0;
-               g->writebuf.__capacity = 0;
-       }
-       
-       if(all) {
-               runtime_m()->gcing = 0;
-               mstats()->enablegc = enablegc;
-               runtime_releaseWorldsema();
-               runtime_startTheWorldWithSema();
-       }
-}
-
-static void
-saveg(G *gp, TRecord *r)
-{
-       int32 n, i;
-       Location locstk[nelem(r->stk)];
-
-       if(gp == runtime_g()) {
-               n = runtime_callers(0, locstk, nelem(r->stk), false);
-               for(i = 0; i < n; i++)
-                       r->stk[i] = locstk[i].pc;
-       }
-       else {
-               // FIXME: Not implemented.
-               n = 0;
-       }
-       if((size_t)n < nelem(r->stk))
-               r->stk[n] = 0;
-}
-
-func GoroutineProfile(b Slice) (n int, ok bool) {
-       uintptr i;
-       TRecord *r;
-       G *gp;
-       
-       ok = false;
-       n = runtime_gcount();
-       if(n <= b.__count) {
-               runtime_acquireWorldsema();
-               runtime_m()->gcing = 1;
-               runtime_stopTheWorldWithSema();
-
-               n = runtime_gcount();
-               if(n <= b.__count) {
-                       G* g = runtime_g();
-                       ok = true;
-                       r = (TRecord*)b.__values;
-                       saveg(g, r++);
-                       for(i = 0; i < runtime_allglen; i++) {
-                               gp = runtime_allg[i];
-                               if(gp == g || gp->atomicstatus == _Gdead)
-                                       continue;
-                               saveg(gp, r++);
-                       }
-               }
-       
-               runtime_m()->gcing = 0;
-               runtime_releaseWorldsema();
-               runtime_startTheWorldWithSema();
-       }
-}
-
-// Tracing of alloc/free/gc.
-
-static Lock tracelock;
-
-static const char*
-typeinfoname(int32 typeinfo)
-{
-       if(typeinfo == TypeInfo_SingleObject)
-               return "single object";
-       else if(typeinfo == TypeInfo_Array)
-               return "array";
-       else if(typeinfo == TypeInfo_Chan)
-               return "channel";
-       runtime_throw("typinfoname: unknown type info");
-       return nil;
-}
-
-void
-runtime_tracealloc(void *p, uintptr size, uintptr typ)
-{
-       const char *name;
-       Type *type;
-
-       runtime_lock(&tracelock);
-       runtime_m()->traceback = 2;
-       type = (Type*)(typ & ~3);
-       name = typeinfoname(typ & 3);
-       if(type == nil)
-               runtime_printf("tracealloc(%p, %p, %s)\n", p, size, name);
-       else    
-               runtime_printf("tracealloc(%p, %p, %s of %S)\n", p, size, name, *type->__reflection);
-       if(runtime_m()->curg == nil || runtime_g() == runtime_m()->curg) {
-               runtime_goroutineheader(runtime_g());
-               runtime_traceback();
-       } else {
-               runtime_goroutineheader(runtime_m()->curg);
-               runtime_traceback();
-       }
-       runtime_printf("\n");
-       runtime_m()->traceback = 0;
-       runtime_unlock(&tracelock);
-}
-
-void
-runtime_tracefree(void *p, uintptr size)
-{
-       runtime_lock(&tracelock);
-       runtime_m()->traceback = 2;
-       runtime_printf("tracefree(%p, %p)\n", p, size);
-       runtime_goroutineheader(runtime_g());
-       runtime_traceback();
-       runtime_printf("\n");
-       runtime_m()->traceback = 0;
-       runtime_unlock(&tracelock);
-}
-
-void
-runtime_tracegc(void)
-{
-       runtime_lock(&tracelock);
-       runtime_m()->traceback = 2;
-       runtime_printf("tracegc()\n");
-       // running on m->g0 stack; show all non-g0 goroutines
-       runtime_tracebackothers(runtime_g());
-       runtime_printf("end tracegc\n");
-       runtime_printf("\n");
-       runtime_m()->traceback = 0;
-       runtime_unlock(&tracelock);
-}
index 246ab7d1b022b89b325c743aa6f2194cc287986c..7d65c4b3b725fae71f56e56ec64fb6e8ade0cdd4 100644 (file)
@@ -657,68 +657,13 @@ runtime_main(void* dummy __attribute__((unused)))
                *(int32*)0 = 0;
 }
 
-void
-runtime_goroutineheader(G *gp)
-{
-       String status;
-       int64 waitfor;
-
-       switch(gp->atomicstatus) {
-       case _Gidle:
-               status = runtime_gostringnocopy((const byte*)"idle");
-               break;
-       case _Grunnable:
-               status = runtime_gostringnocopy((const byte*)"runnable");
-               break;
-       case _Grunning:
-               status = runtime_gostringnocopy((const byte*)"running");
-               break;
-       case _Gsyscall:
-               status = runtime_gostringnocopy((const byte*)"syscall");
-               break;
-       case _Gwaiting:
-               if(gp->waitreason.len > 0)
-                       status = gp->waitreason;
-               else
-                       status = runtime_gostringnocopy((const byte*)"waiting");
-               break;
-       default:
-               status = runtime_gostringnocopy((const byte*)"???");
-               break;
-       }
-
-       // approx time the G is blocked, in minutes
-       waitfor = 0;
-       if((gp->atomicstatus == _Gwaiting || gp->atomicstatus == _Gsyscall) && gp->waitsince != 0)
-               waitfor = (runtime_nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
-
-       if(waitfor < 1)
-               runtime_printf("goroutine %D [%S]:\n", gp->goid, status);
-       else
-               runtime_printf("goroutine %D [%S, %D minutes]:\n", gp->goid, status, waitfor);
-}
-
-void
-runtime_printcreatedby(G *g)
-{
-       if(g != nil && g->gopc != 0 && g->goid != 1) {
-               String fn;
-               String file;
-               intgo line;
-
-               if(__go_file_line(g->gopc - 1, -1, &fn, &file, &line)) {
-                       runtime_printf("created by %S\n", fn);
-                       runtime_printf("\t%S:%D\n", file, (int64) line);
-               }
-       }
-}
-
 void
 runtime_tracebackothers(G * volatile me)
 {
        G * volatile gp;
        Traceback tb;
        int32 traceback;
+       Slice slice;
        volatile uintptr i;
 
        tb.gp = me;
@@ -739,7 +684,10 @@ runtime_tracebackothers(G * volatile me)
                  runtime_gogo(gp);
                }
 
-               runtime_printtrace(tb.locbuf, tb.c, false);
+               slice.__values = &tb.locbuf[0];
+               slice.__count = tb.c;
+               slice.__capacity = tb.c;
+               runtime_printtrace(slice, nil);
                runtime_printcreatedby(gp);
        }
 
@@ -780,7 +728,10 @@ runtime_tracebackothers(G * volatile me)
                                runtime_gogo(gp);
                        }
 
-                       runtime_printtrace(tb.locbuf, tb.c, false);
+                       slice.__values = &tb.locbuf[0];
+                       slice.__count = tb.c;
+                       slice.__capacity = tb.c;
+                       runtime_printtrace(slice, nil);
                        runtime_printcreatedby(gp);
                }
        }
@@ -3597,3 +3548,28 @@ sync_runtime_doSpin()
 {
        runtime_procyield(ACTIVE_SPIN_CNT);
 }
+
+// For Go code to look at variables, until we port proc.go.
+
+extern M** runtime_go_allm(void)
+  __asm__ (GOSYM_PREFIX "runtime.allm");
+
+M**
+runtime_go_allm()
+{
+       return &runtime_allm;
+}
+
+extern Slice runtime_go_allgs(void)
+  __asm__ (GOSYM_PREFIX "runtime.allgs");
+
+Slice
+runtime_go_allgs()
+{
+       Slice s;
+
+       s.__values = runtime_allg;
+       s.__count = runtime_allglen;
+       s.__capacity = allgcap;
+       return s;
+}
index 8e6f1f5052468bd5eb54a74249d49f9d8128157e..70331f4767e7fd7c18768c08021223c3ffd42753 100644 (file)
@@ -90,18 +90,6 @@ runtime_cputicks(void)
 #endif
 }
 
-bool
-runtime_showframe(String s, bool current)
-{
-       static int32 traceback = -1;
-
-       if(current && runtime_m()->throwing > 0)
-               return 1;
-       if(traceback < 0)
-               traceback = runtime_gotraceback(nil);
-       return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0);
-}
-
 // Called to initialize a new m (including the bootstrap m).
 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
 void
index 27b0649f30f922e866df4a01dc03c6be61b0336f..be19e9527ccb2f571c5d2fb2547f7953fa3152e7 100644 (file)
@@ -89,7 +89,7 @@ typedef struct        __go_interface_type     InterfaceType;
 typedef struct __go_map_type           MapType;
 typedef struct __go_channel_type       ChanType;
 
-typedef struct  traceback      Traceback;
+typedef struct  tracebackg     Traceback;
 
 typedef struct location        Location;
 
@@ -261,8 +261,10 @@ enum {
 };
 void   runtime_hashinit(void);
 
-void   runtime_traceback(void);
-void   runtime_tracebackothers(G*);
+void   runtime_traceback(void)
+  __asm__ (GOSYM_PREFIX "runtime.traceback");
+void   runtime_tracebackothers(G*)
+  __asm__ (GOSYM_PREFIX "runtime.tracebackothers");
 enum
 {
        // The maximum number of frames we print for a traceback
@@ -325,8 +327,10 @@ void       runtime_sigenable(uint32 sig);
 void   runtime_sigdisable(uint32 sig);
 void   runtime_sigignore(uint32 sig);
 int32  runtime_gotraceback(bool *crash);
-void   runtime_goroutineheader(G*);
-void   runtime_printtrace(Location*, int32, bool);
+void   runtime_goroutineheader(G*)
+  __asm__ (GOSYM_PREFIX "runtime.goroutineheader");
+void   runtime_printtrace(Slice, G*)
+  __asm__ (GOSYM_PREFIX "runtime.printtrace");
 #define runtime_open(p, f, m) open((p), (f), (m))
 #define runtime_read(d, v, n) read((d), (v), (n))
 #define runtime_write(d, v, n) write((d), (v), (n))
@@ -561,8 +565,8 @@ void        runtime_lockOSThread(void);
 void   runtime_unlockOSThread(void);
 bool   runtime_lockedOSThread(void);
 
-bool   runtime_showframe(String, bool);
-void   runtime_printcreatedby(G*);
+void   runtime_printcreatedby(G*)
+  __asm__(GOSYM_PREFIX "runtime.printcreatedby");
 
 uintptr        runtime_memlimit(void);