github.com/matrixorigin/matrixone@v1.2.0/pkg/common/moprobe/probe.go (about)

     1  // Copyright 2021 - 2023 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //
    16  // Poorman's usdt probe.
    17  // Using bpftrace to trace go user space code is hard.  There are a few problems with go runtime
    18  //  1. you simply cannot use uretprobe.  Go runtime may move stack around and return probe simply
    19  //     does not work.
    20  //  2. the argument to uprobe is rather hard to get.  Golang ABI changed so most of the stuff you
    21  //     find on the web is obsolete.
    22  //  3. there are ways of creating usdt with rather sophisticated bpf hacks, but I don't think it
    23  //     can be understood by meer mortal.
    24  //  4. thread id is not meaningful in go.  goroutine id is also fishy and rather hard to get.  Thread
    25  //     id is extremely important/useful for tracing.
    26  //
    27  // Anyway, I didn't find a "satisfying" solution, so let's roll out our own.   It is extremely simple.
    28  // When you need a static tracepoint, simply create a function here in this file.  The function should take
    29  // *AT MOST* 9 arguments, *ALL* of them *int64*.  If you want to pass in a string, then use 2 params, a pointer
    30  // that is converted to int64, and a length (you don't need this one if length is not needed).  The arguments
    31  // are available in bpftrace in registers.  DO NOT pass in complex data structures as arg.  Go will put those
    32  // on stack and it is simply impossible for bpftrace to decode.
    33  //
    34  // We suggest you always use first argument as a tag -- this is roughly the tid of C program.  You use this
    35  // to track function call and return so that you won't mix call/return from different go routines.  A pointer
    36  // of context, or go data structure converted to int64 usually works well.
    37  //
    38  // Not the noinline pragma. We will use bpftrace uprobe -- it can not be probed if the function is inlined.
    39  //
    40  // The following is here for reference.   See latest golang ABI for any changes.
    41  //
    42  // For AMD64, the register for args are
    43  // 	ax, bx, cx, di, si, r8, r9, r10, r11
    44  // Note that bpftrace does not use eax, rax, etc.   It is simply ax.   You can print out with %ld or %lx to get
    45  // the full 8 bytes.
    46  //
    47  // For arm64, the registers are r0 - r15.
    48  //
    49  
    50  package moprobe
    51  
    52  import (
    53  	"context"
    54  	gotrace "runtime/trace"
    55  	"unsafe"
    56  )
    57  
    58  type RegionType int64
    59  
    60  const (
    61  	GenericRegion RegionType = iota
    62  	PartitionStateHandleInsert
    63  	PartitionStateHandleDel
    64  	PartitionStateHandleMetaInsert
    65  	PartitionStateHandleMetaDelete
    66  	SubscriptionPullLogTail
    67  	RPCStreamReceive
    68  	TxnStoreWaitWALFlush
    69  	TxnTableDoPrecommitDedupByPK
    70  	LogtailConsume
    71  	RegionTypeMax
    72  )
    73  
    74  var regionTypeStr = [RegionTypeMax]string{
    75  	"",
    76  	"partiton state insert",
    77  	"partiton state del",
    78  	"partiton state metainsert",
    79  	"partiton state meta delete",
    80  	"subscription pull logtail",
    81  	"rpc stream receive",
    82  	"txnstore wait wal flush",
    83  	"txntable do precommit dedup by pk",
    84  	"logtail consume",
    85  }
    86  
    87  func WithRegion(ctx context.Context, rt RegionType, fn func()) {
    88  	WithArgAndFn(ctx, rt, 0, 0, fn)
    89  }
    90  
    91  func WithArg(ctx context.Context, rt RegionType, arg1, arg2 int64) {
    92  	WithArgAndFn(ctx, rt, arg1, arg2, nil)
    93  }
    94  
    95  func WithArgAndFn(ctx context.Context, rt RegionType, arg1, arg2 int64, fn func()) {
    96  	tag := uintptr(unsafe.Pointer(&ctx))
    97  	withTwoArg(tag, rt, arg1, arg2)
    98  	if fn != nil {
    99  		gotrace.WithRegion(ctx, regionTypeStr[rt], fn)
   100  		withTwoArgRet(tag, rt, arg1, arg2)
   101  	}
   102  }
   103  
   104  //go:noinline
   105  func withTwoArg(tag uintptr, rt RegionType, v1, v2 int64) {
   106  }
   107  
   108  //go:noinline
   109  func withTwoArgRet(tag uintptr, rt RegionType, v1, v2 int64) {
   110  }