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 }