github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libgo/go/runtime/pprof/pprof.go (about)

     1  // Copyright 2010 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package pprof writes runtime profiling data in the format expected
     6  // by the pprof visualization tool.
     7  // For more information about pprof, see
     8  // http://code.google.com/p/google-perftools/.
     9  package pprof
    10  
    11  import (
    12  	"bufio"
    13  	"bytes"
    14  	"fmt"
    15  	"io"
    16  	"runtime"
    17  	"sort"
    18  	"strings"
    19  	"sync"
    20  	"text/tabwriter"
    21  )
    22  
    23  // BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
    24  // See http://golang.org/issue/6047 for details.
    25  
    26  // A Profile is a collection of stack traces showing the call sequences
    27  // that led to instances of a particular event, such as allocation.
    28  // Packages can create and maintain their own profiles; the most common
    29  // use is for tracking resources that must be explicitly closed, such as files
    30  // or network connections.
    31  //
    32  // A Profile's methods can be called from multiple goroutines simultaneously.
    33  //
    34  // Each Profile has a unique name.  A few profiles are predefined:
    35  //
    36  //	goroutine    - stack traces of all current goroutines
    37  //	heap         - a sampling of all heap allocations
    38  //	threadcreate - stack traces that led to the creation of new OS threads
    39  //	block        - stack traces that led to blocking on synchronization primitives
    40  //
    41  // These predefined profiles maintain themselves and panic on an explicit
    42  // Add or Remove method call.
    43  //
    44  // The CPU profile is not available as a Profile.  It has a special API,
    45  // the StartCPUProfile and StopCPUProfile functions, because it streams
    46  // output to a writer during profiling.
    47  //
    48  type Profile struct {
    49  	name  string
    50  	mu    sync.Mutex
    51  	m     map[interface{}][]uintptr
    52  	count func() int
    53  	write func(io.Writer, int) error
    54  }
    55  
    56  // profiles records all registered profiles.
    57  var profiles struct {
    58  	mu sync.Mutex
    59  	m  map[string]*Profile
    60  }
    61  
    62  var goroutineProfile = &Profile{
    63  	name:  "goroutine",
    64  	count: countGoroutine,
    65  	write: writeGoroutine,
    66  }
    67  
    68  var threadcreateProfile = &Profile{
    69  	name:  "threadcreate",
    70  	count: countThreadCreate,
    71  	write: writeThreadCreate,
    72  }
    73  
    74  var heapProfile = &Profile{
    75  	name:  "heap",
    76  	count: countHeap,
    77  	write: writeHeap,
    78  }
    79  
    80  var blockProfile = &Profile{
    81  	name:  "block",
    82  	count: countBlock,
    83  	write: writeBlock,
    84  }
    85  
    86  func lockProfiles() {
    87  	profiles.mu.Lock()
    88  	if profiles.m == nil {
    89  		// Initial built-in profiles.
    90  		profiles.m = map[string]*Profile{
    91  			"goroutine":    goroutineProfile,
    92  			"threadcreate": threadcreateProfile,
    93  			"heap":         heapProfile,
    94  			"block":        blockProfile,
    95  		}
    96  	}
    97  }
    98  
    99  func unlockProfiles() {
   100  	profiles.mu.Unlock()
   101  }
   102  
   103  // NewProfile creates a new profile with the given name.
   104  // If a profile with that name already exists, NewProfile panics.
   105  // The convention is to use a 'import/path.' prefix to create
   106  // separate name spaces for each package.
   107  func NewProfile(name string) *Profile {
   108  	lockProfiles()
   109  	defer unlockProfiles()
   110  	if name == "" {
   111  		panic("pprof: NewProfile with empty name")
   112  	}
   113  	if profiles.m[name] != nil {
   114  		panic("pprof: NewProfile name already in use: " + name)
   115  	}
   116  	p := &Profile{
   117  		name: name,
   118  		m:    map[interface{}][]uintptr{},
   119  	}
   120  	profiles.m[name] = p
   121  	return p
   122  }
   123  
   124  // Lookup returns the profile with the given name, or nil if no such profile exists.
   125  func Lookup(name string) *Profile {
   126  	lockProfiles()
   127  	defer unlockProfiles()
   128  	return profiles.m[name]
   129  }
   130  
   131  // Profiles returns a slice of all the known profiles, sorted by name.
   132  func Profiles() []*Profile {
   133  	lockProfiles()
   134  	defer unlockProfiles()
   135  
   136  	var all []*Profile
   137  	for _, p := range profiles.m {
   138  		all = append(all, p)
   139  	}
   140  
   141  	sort.Sort(byName(all))
   142  	return all
   143  }
   144  
   145  type byName []*Profile
   146  
   147  func (x byName) Len() int           { return len(x) }
   148  func (x byName) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   149  func (x byName) Less(i, j int) bool { return x[i].name < x[j].name }
   150  
   151  // Name returns this profile's name, which can be passed to Lookup to reobtain the profile.
   152  func (p *Profile) Name() string {
   153  	return p.name
   154  }
   155  
   156  // Count returns the number of execution stacks currently in the profile.
   157  func (p *Profile) Count() int {
   158  	p.mu.Lock()
   159  	defer p.mu.Unlock()
   160  	if p.count != nil {
   161  		return p.count()
   162  	}
   163  	return len(p.m)
   164  }
   165  
   166  // Add adds the current execution stack to the profile, associated with value.
   167  // Add stores value in an internal map, so value must be suitable for use as
   168  // a map key and will not be garbage collected until the corresponding
   169  // call to Remove.  Add panics if the profile already contains a stack for value.
   170  //
   171  // The skip parameter has the same meaning as runtime.Caller's skip
   172  // and controls where the stack trace begins.  Passing skip=0 begins the
   173  // trace in the function calling Add.  For example, given this
   174  // execution stack:
   175  //
   176  //	Add
   177  //	called from rpc.NewClient
   178  //	called from mypkg.Run
   179  //	called from main.main
   180  //
   181  // Passing skip=0 begins the stack trace at the call to Add inside rpc.NewClient.
   182  // Passing skip=1 begins the stack trace at the call to NewClient inside mypkg.Run.
   183  //
   184  func (p *Profile) Add(value interface{}, skip int) {
   185  	if p.name == "" {
   186  		panic("pprof: use of uninitialized Profile")
   187  	}
   188  	if p.write != nil {
   189  		panic("pprof: Add called on built-in Profile " + p.name)
   190  	}
   191  
   192  	stk := make([]uintptr, 32)
   193  	n := runtime.Callers(skip+1, stk[:])
   194  
   195  	p.mu.Lock()
   196  	defer p.mu.Unlock()
   197  	if p.m[value] != nil {
   198  		panic("pprof: Profile.Add of duplicate value")
   199  	}
   200  	p.m[value] = stk[:n]
   201  }
   202  
   203  // Remove removes the execution stack associated with value from the profile.
   204  // It is a no-op if the value is not in the profile.
   205  func (p *Profile) Remove(value interface{}) {
   206  	p.mu.Lock()
   207  	defer p.mu.Unlock()
   208  	delete(p.m, value)
   209  }
   210  
   211  // WriteTo writes a pprof-formatted snapshot of the profile to w.
   212  // If a write to w returns an error, WriteTo returns that error.
   213  // Otherwise, WriteTo returns nil.
   214  //
   215  // The debug parameter enables additional output.
   216  // Passing debug=0 prints only the hexadecimal addresses that pprof needs.
   217  // Passing debug=1 adds comments translating addresses to function names
   218  // and line numbers, so that a programmer can read the profile without tools.
   219  //
   220  // The predefined profiles may assign meaning to other debug values;
   221  // for example, when printing the "goroutine" profile, debug=2 means to
   222  // print the goroutine stacks in the same form that a Go program uses
   223  // when dying due to an unrecovered panic.
   224  func (p *Profile) WriteTo(w io.Writer, debug int) error {
   225  	if p.name == "" {
   226  		panic("pprof: use of zero Profile")
   227  	}
   228  	if p.write != nil {
   229  		return p.write(w, debug)
   230  	}
   231  
   232  	// Obtain consistent snapshot under lock; then process without lock.
   233  	var all [][]uintptr
   234  	p.mu.Lock()
   235  	for _, stk := range p.m {
   236  		all = append(all, stk)
   237  	}
   238  	p.mu.Unlock()
   239  
   240  	// Map order is non-deterministic; make output deterministic.
   241  	sort.Sort(stackProfile(all))
   242  
   243  	return printCountProfile(w, debug, p.name, stackProfile(all))
   244  }
   245  
   246  type stackProfile [][]uintptr
   247  
   248  func (x stackProfile) Len() int              { return len(x) }
   249  func (x stackProfile) Stack(i int) []uintptr { return x[i] }
   250  func (x stackProfile) Swap(i, j int)         { x[i], x[j] = x[j], x[i] }
   251  func (x stackProfile) Less(i, j int) bool {
   252  	t, u := x[i], x[j]
   253  	for k := 0; k < len(t) && k < len(u); k++ {
   254  		if t[k] != u[k] {
   255  			return t[k] < u[k]
   256  		}
   257  	}
   258  	return len(t) < len(u)
   259  }
   260  
   261  // A countProfile is a set of stack traces to be printed as counts
   262  // grouped by stack trace.  There are multiple implementations:
   263  // all that matters is that we can find out how many traces there are
   264  // and obtain each trace in turn.
   265  type countProfile interface {
   266  	Len() int
   267  	Stack(i int) []uintptr
   268  }
   269  
   270  // printCountProfile prints a countProfile at the specified debug level.
   271  func printCountProfile(w io.Writer, debug int, name string, p countProfile) error {
   272  	b := bufio.NewWriter(w)
   273  	var tw *tabwriter.Writer
   274  	w = b
   275  	if debug > 0 {
   276  		tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
   277  		w = tw
   278  	}
   279  
   280  	fmt.Fprintf(w, "%s profile: total %d\n", name, p.Len())
   281  
   282  	// Build count of each stack.
   283  	var buf bytes.Buffer
   284  	key := func(stk []uintptr) string {
   285  		buf.Reset()
   286  		fmt.Fprintf(&buf, "@")
   287  		for _, pc := range stk {
   288  			fmt.Fprintf(&buf, " %#x", pc)
   289  		}
   290  		return buf.String()
   291  	}
   292  	m := map[string]int{}
   293  	n := p.Len()
   294  	for i := 0; i < n; i++ {
   295  		m[key(p.Stack(i))]++
   296  	}
   297  
   298  	// Print stacks, listing count on first occurrence of a unique stack.
   299  	for i := 0; i < n; i++ {
   300  		stk := p.Stack(i)
   301  		s := key(stk)
   302  		if count := m[s]; count != 0 {
   303  			fmt.Fprintf(w, "%d %s\n", count, s)
   304  			if debug > 0 {
   305  				printStackRecord(w, stk, false)
   306  			}
   307  			delete(m, s)
   308  		}
   309  	}
   310  
   311  	if tw != nil {
   312  		tw.Flush()
   313  	}
   314  	return b.Flush()
   315  }
   316  
   317  // printStackRecord prints the function + source line information
   318  // for a single stack trace.
   319  func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
   320  	show := allFrames
   321  	wasPanic := false
   322  	for i, pc := range stk {
   323  		f := runtime.FuncForPC(pc)
   324  		if f == nil {
   325  			show = true
   326  			fmt.Fprintf(w, "#\t%#x\n", pc)
   327  			wasPanic = false
   328  		} else {
   329  			tracepc := pc
   330  			// Back up to call instruction.
   331  			if i > 0 && pc > f.Entry() && !wasPanic {
   332  				if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
   333  					tracepc--
   334  				} else if runtime.GOARCH == "s390" || runtime.GOARCH == "s390x" {
   335  					// only works if function was called
   336  					// with the brasl instruction (or a
   337  					// different 6-byte instruction).
   338  					tracepc -= 6
   339  				} else {
   340  					tracepc -= 4 // arm, etc
   341  				}
   342  			}
   343  			file, line := f.FileLine(tracepc)
   344  			name := f.Name()
   345  			// Hide runtime.goexit and any runtime functions at the beginning.
   346  			// This is useful mainly for allocation traces.
   347  			wasPanic = name == "runtime.panic"
   348  			if name == "runtime.goexit" || !show && (strings.HasPrefix(name, "runtime.") || strings.HasPrefix(name, "runtime_")) {
   349  				continue
   350  			}
   351  			if !show && !strings.Contains(name, ".") && strings.HasPrefix(name, "__go_") {
   352  				continue
   353  			}
   354  			show = true
   355  			fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", pc, name, pc-f.Entry(), file, line)
   356  		}
   357  	}
   358  	if !show {
   359  		// We didn't print anything; do it again,
   360  		// and this time include runtime functions.
   361  		printStackRecord(w, stk, true)
   362  		return
   363  	}
   364  	fmt.Fprintf(w, "\n")
   365  }
   366  
   367  // Interface to system profiles.
   368  
   369  type byInUseBytes []runtime.MemProfileRecord
   370  
   371  func (x byInUseBytes) Len() int           { return len(x) }
   372  func (x byInUseBytes) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   373  func (x byInUseBytes) Less(i, j int) bool { return x[i].InUseBytes() > x[j].InUseBytes() }
   374  
   375  // WriteHeapProfile is shorthand for Lookup("heap").WriteTo(w, 0).
   376  // It is preserved for backwards compatibility.
   377  func WriteHeapProfile(w io.Writer) error {
   378  	return writeHeap(w, 0)
   379  }
   380  
   381  // countHeap returns the number of records in the heap profile.
   382  func countHeap() int {
   383  	n, _ := runtime.MemProfile(nil, true)
   384  	return n
   385  }
   386  
   387  // writeHeap writes the current runtime heap profile to w.
   388  func writeHeap(w io.Writer, debug int) error {
   389  	// Find out how many records there are (MemProfile(nil, true)),
   390  	// allocate that many records, and get the data.
   391  	// There's a race—more records might be added between
   392  	// the two calls—so allocate a few extra records for safety
   393  	// and also try again if we're very unlucky.
   394  	// The loop should only execute one iteration in the common case.
   395  	var p []runtime.MemProfileRecord
   396  	n, ok := runtime.MemProfile(nil, true)
   397  	for {
   398  		// Allocate room for a slightly bigger profile,
   399  		// in case a few more entries have been added
   400  		// since the call to MemProfile.
   401  		p = make([]runtime.MemProfileRecord, n+50)
   402  		n, ok = runtime.MemProfile(p, true)
   403  		if ok {
   404  			p = p[0:n]
   405  			break
   406  		}
   407  		// Profile grew; try again.
   408  	}
   409  
   410  	sort.Sort(byInUseBytes(p))
   411  
   412  	b := bufio.NewWriter(w)
   413  	var tw *tabwriter.Writer
   414  	w = b
   415  	if debug > 0 {
   416  		tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
   417  		w = tw
   418  	}
   419  
   420  	var total runtime.MemProfileRecord
   421  	for i := range p {
   422  		r := &p[i]
   423  		total.AllocBytes += r.AllocBytes
   424  		total.AllocObjects += r.AllocObjects
   425  		total.FreeBytes += r.FreeBytes
   426  		total.FreeObjects += r.FreeObjects
   427  	}
   428  
   429  	// Technically the rate is MemProfileRate not 2*MemProfileRate,
   430  	// but early versions of the C++ heap profiler reported 2*MemProfileRate,
   431  	// so that's what pprof has come to expect.
   432  	fmt.Fprintf(w, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
   433  		total.InUseObjects(), total.InUseBytes(),
   434  		total.AllocObjects, total.AllocBytes,
   435  		2*runtime.MemProfileRate)
   436  
   437  	for i := range p {
   438  		r := &p[i]
   439  		fmt.Fprintf(w, "%d: %d [%d: %d] @",
   440  			r.InUseObjects(), r.InUseBytes(),
   441  			r.AllocObjects, r.AllocBytes)
   442  		for _, pc := range r.Stack() {
   443  			fmt.Fprintf(w, " %#x", pc)
   444  		}
   445  		fmt.Fprintf(w, "\n")
   446  		if debug > 0 {
   447  			printStackRecord(w, r.Stack(), false)
   448  		}
   449  	}
   450  
   451  	// Print memstats information too.
   452  	// Pprof will ignore, but useful for people
   453  	if debug > 0 {
   454  		s := new(runtime.MemStats)
   455  		runtime.ReadMemStats(s)
   456  		fmt.Fprintf(w, "\n# runtime.MemStats\n")
   457  		fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
   458  		fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
   459  		fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
   460  		fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
   461  		fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
   462  		fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
   463  
   464  		fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
   465  		fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
   466  		fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
   467  		fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
   468  		fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
   469  		fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
   470  
   471  		fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
   472  		fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
   473  		fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
   474  		fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
   475  
   476  		fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
   477  		fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
   478  		fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
   479  		fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
   480  		fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
   481  	}
   482  
   483  	if tw != nil {
   484  		tw.Flush()
   485  	}
   486  	return b.Flush()
   487  }
   488  
   489  // countThreadCreate returns the size of the current ThreadCreateProfile.
   490  func countThreadCreate() int {
   491  	n, _ := runtime.ThreadCreateProfile(nil)
   492  	return n
   493  }
   494  
   495  // writeThreadCreate writes the current runtime ThreadCreateProfile to w.
   496  func writeThreadCreate(w io.Writer, debug int) error {
   497  	return writeRuntimeProfile(w, debug, "threadcreate", runtime.ThreadCreateProfile)
   498  }
   499  
   500  // countGoroutine returns the number of goroutines.
   501  func countGoroutine() int {
   502  	return runtime.NumGoroutine()
   503  }
   504  
   505  // writeGoroutine writes the current runtime GoroutineProfile to w.
   506  func writeGoroutine(w io.Writer, debug int) error {
   507  	if debug >= 2 {
   508  		return writeGoroutineStacks(w)
   509  	}
   510  	return writeRuntimeProfile(w, debug, "goroutine", runtime.GoroutineProfile)
   511  }
   512  
   513  func writeGoroutineStacks(w io.Writer) error {
   514  	// We don't know how big the buffer needs to be to collect
   515  	// all the goroutines.  Start with 1 MB and try a few times, doubling each time.
   516  	// Give up and use a truncated trace if 64 MB is not enough.
   517  	buf := make([]byte, 1<<20)
   518  	for i := 0; ; i++ {
   519  		n := runtime.Stack(buf, true)
   520  		if n < len(buf) {
   521  			buf = buf[:n]
   522  			break
   523  		}
   524  		if len(buf) >= 64<<20 {
   525  			// Filled 64 MB - stop there.
   526  			break
   527  		}
   528  		buf = make([]byte, 2*len(buf))
   529  	}
   530  	_, err := w.Write(buf)
   531  	return err
   532  }
   533  
   534  func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord) (int, bool)) error {
   535  	// Find out how many records there are (fetch(nil)),
   536  	// allocate that many records, and get the data.
   537  	// There's a race—more records might be added between
   538  	// the two calls—so allocate a few extra records for safety
   539  	// and also try again if we're very unlucky.
   540  	// The loop should only execute one iteration in the common case.
   541  	var p []runtime.StackRecord
   542  	n, ok := fetch(nil)
   543  	for {
   544  		// Allocate room for a slightly bigger profile,
   545  		// in case a few more entries have been added
   546  		// since the call to ThreadProfile.
   547  		p = make([]runtime.StackRecord, n+10)
   548  		n, ok = fetch(p)
   549  		if ok {
   550  			p = p[0:n]
   551  			break
   552  		}
   553  		// Profile grew; try again.
   554  	}
   555  
   556  	return printCountProfile(w, debug, name, runtimeProfile(p))
   557  }
   558  
   559  type runtimeProfile []runtime.StackRecord
   560  
   561  func (p runtimeProfile) Len() int              { return len(p) }
   562  func (p runtimeProfile) Stack(i int) []uintptr { return p[i].Stack() }
   563  
   564  var cpu struct {
   565  	sync.Mutex
   566  	profiling bool
   567  	done      chan bool
   568  }
   569  
   570  // StartCPUProfile enables CPU profiling for the current process.
   571  // While profiling, the profile will be buffered and written to w.
   572  // StartCPUProfile returns an error if profiling is already enabled.
   573  func StartCPUProfile(w io.Writer) error {
   574  	// The runtime routines allow a variable profiling rate,
   575  	// but in practice operating systems cannot trigger signals
   576  	// at more than about 500 Hz, and our processing of the
   577  	// signal is not cheap (mostly getting the stack trace).
   578  	// 100 Hz is a reasonable choice: it is frequent enough to
   579  	// produce useful data, rare enough not to bog down the
   580  	// system, and a nice round number to make it easy to
   581  	// convert sample counts to seconds.  Instead of requiring
   582  	// each client to specify the frequency, we hard code it.
   583  	const hz = 100
   584  
   585  	cpu.Lock()
   586  	defer cpu.Unlock()
   587  	if cpu.done == nil {
   588  		cpu.done = make(chan bool)
   589  	}
   590  	// Double-check.
   591  	if cpu.profiling {
   592  		return fmt.Errorf("cpu profiling already in use")
   593  	}
   594  	cpu.profiling = true
   595  	runtime.SetCPUProfileRate(hz)
   596  	go profileWriter(w)
   597  	return nil
   598  }
   599  
   600  func profileWriter(w io.Writer) {
   601  	for {
   602  		data := runtime.CPUProfile()
   603  		if data == nil {
   604  			break
   605  		}
   606  		w.Write(data)
   607  	}
   608  	cpu.done <- true
   609  }
   610  
   611  // StopCPUProfile stops the current CPU profile, if any.
   612  // StopCPUProfile only returns after all the writes for the
   613  // profile have completed.
   614  func StopCPUProfile() {
   615  	cpu.Lock()
   616  	defer cpu.Unlock()
   617  
   618  	if !cpu.profiling {
   619  		return
   620  	}
   621  	cpu.profiling = false
   622  	runtime.SetCPUProfileRate(0)
   623  	<-cpu.done
   624  }
   625  
   626  type byCycles []runtime.BlockProfileRecord
   627  
   628  func (x byCycles) Len() int           { return len(x) }
   629  func (x byCycles) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   630  func (x byCycles) Less(i, j int) bool { return x[i].Cycles > x[j].Cycles }
   631  
   632  // countBlock returns the number of records in the blocking profile.
   633  func countBlock() int {
   634  	n, _ := runtime.BlockProfile(nil)
   635  	return n
   636  }
   637  
   638  // writeBlock writes the current blocking profile to w.
   639  func writeBlock(w io.Writer, debug int) error {
   640  	var p []runtime.BlockProfileRecord
   641  	n, ok := runtime.BlockProfile(nil)
   642  	for {
   643  		p = make([]runtime.BlockProfileRecord, n+50)
   644  		n, ok = runtime.BlockProfile(p)
   645  		if ok {
   646  			p = p[:n]
   647  			break
   648  		}
   649  	}
   650  
   651  	sort.Sort(byCycles(p))
   652  
   653  	b := bufio.NewWriter(w)
   654  	var tw *tabwriter.Writer
   655  	w = b
   656  	if debug > 0 {
   657  		tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
   658  		w = tw
   659  	}
   660  
   661  	fmt.Fprintf(w, "--- contention:\n")
   662  	fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond())
   663  	for i := range p {
   664  		r := &p[i]
   665  		fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count)
   666  		for _, pc := range r.Stack() {
   667  			fmt.Fprintf(w, " %#x", pc)
   668  		}
   669  		fmt.Fprint(w, "\n")
   670  		if debug > 0 {
   671  			printStackRecord(w, r.Stack(), true)
   672  		}
   673  	}
   674  
   675  	if tw != nil {
   676  		tw.Flush()
   677  	}
   678  	return b.Flush()
   679  }
   680  
   681  func runtime_cyclesPerSecond() int64