Source file src/runtime/trace/trace.go

     1  // Copyright 2015 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 trace contains facilities for programs to generate traces
     6  // for the Go execution tracer.
     7  //
     8  // Tracing runtime activities
     9  //
    10  // The execution trace captures a wide range of execution events such as
    11  // goroutine creation/blocking/unblocking, syscall enter/exit/block,
    12  // GC-related events, changes of heap size, processor start/stop, etc.
    13  // A precise nanosecond-precision timestamp and a stack trace is
    14  // captured for most events. The generated trace can be interpreted
    15  // using `go tool trace`.
    16  //
    17  // Support for tracing tests and benchmarks built with the standard
    18  // testing package is built into `go test`. For example, the following
    19  // command runs the test in the current directory and writes the trace
    20  // file (trace.out).
    21  //
    22  //    go test -trace=trace.out
    23  //
    24  // This runtime/trace package provides APIs to add equivalent tracing
    25  // support to a standalone program. See the Example that demonstrates
    26  // how to use this API to enable tracing.
    27  //
    28  // There is also a standard HTTP interface to trace data. Adding the
    29  // following line will install a handler under the /debug/pprof/trace URL
    30  // to download a live trace:
    31  //
    32  //     import _ "net/http/pprof"
    33  //
    34  // See the net/http/pprof package for more details about all of the
    35  // debug endpoints installed by this import.
    36  //
    37  // User annotation
    38  //
    39  // Package trace provides user annotation APIs that can be used to
    40  // log interesting events during execution.
    41  //
    42  // There are three types of user annotations: log messages, regions,
    43  // and tasks.
    44  //
    45  // Log emits a timestamped message to the execution trace along with
    46  // additional information such as the category of the message and
    47  // which goroutine called Log. The execution tracer provides UIs to filter
    48  // and group goroutines using the log category and the message supplied
    49  // in Log.
    50  //
    51  // A region is for logging a time interval during a goroutine's execution.
    52  // By definition, a region starts and ends in the same goroutine.
    53  // Regions can be nested to represent subintervals.
    54  // For example, the following code records four regions in the execution
    55  // trace to trace the durations of sequential steps in a cappuccino making
    56  // operation.
    57  //
    58  //   trace.WithRegion(ctx, "makeCappuccino", func() {
    59  //
    60  //      // orderID allows to identify a specific order
    61  //      // among many cappuccino order region records.
    62  //      trace.Log(ctx, "orderID", orderID)
    63  //
    64  //      trace.WithRegion(ctx, "steamMilk", steamMilk)
    65  //      trace.WithRegion(ctx, "extractCoffee", extractCoffee)
    66  //      trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee)
    67  //   })
    68  //
    69  // A task is a higher-level component that aids tracing of logical
    70  // operations such as an RPC request, an HTTP request, or an
    71  // interesting local operation which may require multiple goroutines
    72  // working together. Since tasks can involve multiple goroutines,
    73  // they are tracked via a context.Context object. NewTask creates
    74  // a new task and embeds it in the returned context.Context object.
    75  // Log messages and regions are attached to the task, if any, in the
    76  // Context passed to Log and WithRegion.
    77  //
    78  // For example, assume that we decided to froth milk, extract coffee,
    79  // and mix milk and coffee in separate goroutines. With a task,
    80  // the trace tool can identify the goroutines involved in a specific
    81  // cappuccino order.
    82  //
    83  //      ctx, task := trace.NewTask(ctx, "makeCappuccino")
    84  //      trace.Log(ctx, "orderID", orderID)
    85  //
    86  //      milk := make(chan bool)
    87  //      espresso := make(chan bool)
    88  //
    89  //      go func() {
    90  //              trace.WithRegion(ctx, "steamMilk", steamMilk)
    91  //              milk <- true
    92  //      }()
    93  //      go func() {
    94  //              trace.WithRegion(ctx, "extractCoffee", extractCoffee)
    95  //              espresso <- true
    96  //      }()
    97  //      go func() {
    98  //              defer task.End() // When assemble is done, the order is complete.
    99  //              <-espresso
   100  //              <-milk
   101  //              trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee)
   102  //      }()
   103  //
   104  //
   105  // The trace tool computes the latency of a task by measuring the
   106  // time between the task creation and the task end and provides
   107  // latency distributions for each task type found in the trace.
   108  package trace
   109  
   110  import (
   111  	"io"
   112  	"runtime"
   113  	"sync"
   114  	"sync/atomic"
   115  )
   116  
   117  // Start enables tracing for the current program.
   118  // While tracing, the trace will be buffered and written to w.
   119  // Start returns an error if tracing is already enabled.
   120  func Start(w io.Writer) error {
   121  	tracing.Lock()
   122  	defer tracing.Unlock()
   123  
   124  	if err := runtime.StartTrace(); err != nil {
   125  		return err
   126  	}
   127  	go func() {
   128  		for {
   129  			data := runtime.ReadTrace()
   130  			if data == nil {
   131  				break
   132  			}
   133  			w.Write(data)
   134  		}
   135  	}()
   136  	atomic.StoreInt32(&tracing.enabled, 1)
   137  	return nil
   138  }
   139  
   140  // Stop stops the current tracing, if any.
   141  // Stop only returns after all the writes for the trace have completed.
   142  func Stop() {
   143  	tracing.Lock()
   144  	defer tracing.Unlock()
   145  	atomic.StoreInt32(&tracing.enabled, 0)
   146  
   147  	runtime.StopTrace()
   148  }
   149  
   150  var tracing struct {
   151  	sync.Mutex       // gate mutators (Start, Stop)
   152  	enabled    int32 // accessed via atomic
   153  }
   154  

View as plain text