github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/profiling/goid_modified.go (about)

     1  //go:build grpcgoid
     2  // +build grpcgoid
     3  
     4  /*
     5   *
     6   * Copyright 2019 gRPC authors.
     7   *
     8   * Licensed under the Apache License, Version 2.0 (the "License");
     9   * you may not use this file except in compliance with the License.
    10   * You may obtain a copy of the License at
    11   *
    12   *     http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing, software
    15   * distributed under the License is distributed on an "AS IS" BASIS,
    16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17   * See the License for the specific language governing permissions and
    18   * limitations under the License.
    19   *
    20   */
    21  
    22  package profiling
    23  
    24  import (
    25  	"runtime"
    26  )
    27  
    28  // This stubbed function usually returns zero (see goid_regular.go); however,
    29  // if grpc is built with `-tags 'grpcgoid'`, a runtime.Goid function, which
    30  // does not exist in the Go standard library, is expected. While not necessary,
    31  // sometimes, visualising grpc profiling data in trace-viewer is much nicer
    32  // with goroutines separated from each other.
    33  //
    34  // Several other approaches were considered before arriving at this:
    35  //
    36  // 1. Using a CGO module: CGO usually has access to some things that regular
    37  //    Go does not. Till go1.4, CGO used to have access to the goroutine struct
    38  //    because the Go runtime was written in C. However, 1.5+ uses a native Go
    39  //    runtime; as a result, CGO does not have access to the goroutine structure
    40  //    anymore in modern Go. Besides, CGO interop wasn't fast enough (estimated
    41  //    to be ~170ns/op). This would also make building grpc require a C
    42  //    compiler, which isn't a requirement currently, breaking a lot of stuff.
    43  //
    44  // 2. Using runtime.Stack stacktrace: While this would remove the need for a
    45  //    modified Go runtime, this is ridiculously slow, thanks to the all the
    46  //    string processing shenanigans required to extract the goroutine ID (about
    47  //    ~2000ns/op).
    48  //
    49  // 3. Using Go version-specific build tags: For any given Go version, the
    50  //    goroutine struct has a fixed structure. As a result, the goroutine ID
    51  //    could be extracted if we know the offset using some assembly. This would
    52  //    be faster then #1 and #2, but is harder to maintain. This would require
    53  //    special Go code that's both architecture-specific and go version-specific
    54  //    (a quadratic number of variants to maintain).
    55  //
    56  // 4. This approach, which requires a simple modification [1] to the Go runtime
    57  //    to expose the current goroutine's ID. This is the chosen approach and it
    58  //    takes about ~2 ns/op, which is negligible in the face of the tens of
    59  //    microseconds that grpc takes to complete a RPC request.
    60  //
    61  // [1] To make the goroutine ID visible to Go programs apply the following
    62  // change to the runtime2.go file in your Go runtime installation:
    63  //
    64  //     diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
    65  //     --- a/src/runtime/runtime2.go
    66  //     +++ b/src/runtime/runtime2.go
    67  //     @@ -392,6 +392,10 @@ type stack struct {
    68  //      	hi uintptr
    69  //      }
    70  //
    71  //     +func Goid() int64 {
    72  //     +  return getg().goid
    73  //     +}
    74  //     +
    75  //      type g struct {
    76  //      	// Stack parameters.
    77  //      	// stack describes the actual stack memory: [stack.lo, stack.hi).
    78  //
    79  // The exposed runtime.Goid() function will return a int64 goroutine ID.
    80  func goid() int64 {
    81  	return runtime.Goid()
    82  }