-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
*: Optimize executor runtime stats performance #1532
Changes from 9 commits
c721978
2be7e83
6a0fcd1
d41143c
865f20f
7bd30c8
eaab49f
327eca3
40250c9
eb6ba21
562e6e2
37a5ea0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,7 +127,11 @@ func (s *RegionRequestSender) String() string { | |
|
||
// RegionRequestRuntimeStats records the runtime stats of send region requests. | ||
type RegionRequestRuntimeStats struct { | ||
RPCStats map[tikvrpc.CmdType]*RPCRuntimeStats | ||
// FirstRPCStats is the stats of first kinds of rpc request, since in most cases, only one kind of rpc request is sent at a time, | ||
// this is to avoid allocating map memory. | ||
FirstRPCStats RPCRuntimeStats | ||
// OtherRPCStatsMap uses to record another types of RPC requests. | ||
OtherRPCStatsMap map[tikvrpc.CmdType]*RPCRuntimeStats | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a suggestion, since one RegionRequestSender typically only send one (or a few) kind(s) of RPC, I guess we can just use a slice here to make the code clean and simple. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great, done. |
||
RequestErrorStats | ||
} | ||
|
||
|
@@ -141,30 +145,60 @@ type RequestErrorStats struct { | |
|
||
// NewRegionRequestRuntimeStats returns a new RegionRequestRuntimeStats. | ||
func NewRegionRequestRuntimeStats() *RegionRequestRuntimeStats { | ||
return &RegionRequestRuntimeStats{ | ||
RPCStats: make(map[tikvrpc.CmdType]*RPCRuntimeStats), | ||
} | ||
return &RegionRequestRuntimeStats{} | ||
} | ||
|
||
// RPCRuntimeStats indicates the RPC request count and consume time. | ||
type RPCRuntimeStats struct { | ||
Count int64 | ||
Cmd tikvrpc.CmdType | ||
Count uint32 | ||
// Send region request consume time. | ||
Consume int64 | ||
Consume time.Duration | ||
} | ||
|
||
// RecordRPCRuntimeStats uses to record the rpc count and duration stats. | ||
func (r *RegionRequestRuntimeStats) RecordRPCRuntimeStats(cmd tikvrpc.CmdType, d time.Duration) { | ||
stat, ok := r.RPCStats[cmd] | ||
if r.FirstRPCStats.Count == 0 || r.FirstRPCStats.Cmd == cmd { | ||
r.FirstRPCStats.Cmd = cmd | ||
r.FirstRPCStats.Count++ | ||
r.FirstRPCStats.Consume += d | ||
return | ||
} | ||
if r.OtherRPCStatsMap == nil { | ||
r.OtherRPCStatsMap = make(map[tikvrpc.CmdType]*RPCRuntimeStats) | ||
} | ||
stat, ok := r.OtherRPCStatsMap[cmd] | ||
if !ok { | ||
r.RPCStats[cmd] = &RPCRuntimeStats{ | ||
r.OtherRPCStatsMap[cmd] = &RPCRuntimeStats{ | ||
Cmd: cmd, | ||
Count: 1, | ||
Consume: int64(d), | ||
Consume: d, | ||
} | ||
return | ||
} | ||
stat.Count++ | ||
stat.Consume += int64(d) | ||
stat.Consume += d | ||
} | ||
|
||
// GetRPCCount returns the total rpc types count. | ||
func (r *RegionRequestRuntimeStats) GetRPCCount() int { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great, done. |
||
if r.FirstRPCStats.Count > 0 { | ||
return len(r.OtherRPCStatsMap) + 1 | ||
} | ||
return len(r.OtherRPCStatsMap) | ||
} | ||
|
||
// GetCmdRPCCount returns the rpc count of the specified cmd type. | ||
func (r *RegionRequestRuntimeStats) GetCmdRPCCount(cmd tikvrpc.CmdType) uint32 { | ||
if r.FirstRPCStats.Cmd == cmd { | ||
return r.FirstRPCStats.Count | ||
} | ||
if r.OtherRPCStatsMap != nil { | ||
if stats := r.OtherRPCStatsMap[cmd]; stats != nil { | ||
return stats.Count | ||
} | ||
} | ||
return 0 | ||
} | ||
|
||
// RecordRPCErrorStats uses to record the request error(region error label and rpc error) info and count. | ||
|
@@ -198,16 +232,14 @@ func (r *RegionRequestRuntimeStats) String() string { | |
return "" | ||
} | ||
var builder strings.Builder | ||
for k, v := range r.RPCStats { | ||
if r.FirstRPCStats.Count > 0 { | ||
r.FirstRPCStats.buildString(&builder) | ||
} | ||
for _, v := range r.OtherRPCStatsMap { | ||
if builder.Len() > 0 { | ||
builder.WriteByte(',') | ||
} | ||
builder.WriteString(k.String()) | ||
builder.WriteString(":{num_rpc:") | ||
builder.WriteString(strconv.FormatInt(v.Count, 10)) | ||
builder.WriteString(", total_time:") | ||
builder.WriteString(util.FormatDuration(time.Duration(v.Consume))) | ||
builder.WriteString("}") | ||
v.buildString(&builder) | ||
} | ||
if errStatsStr := r.RequestErrorStats.String(); errStatsStr != "" { | ||
builder.WriteString(", rpc_errors:") | ||
|
@@ -216,6 +248,15 @@ func (r *RegionRequestRuntimeStats) String() string { | |
return builder.String() | ||
} | ||
|
||
func (s *RPCRuntimeStats) buildString(builder *strings.Builder) { | ||
builder.WriteString(s.Cmd.String()) | ||
builder.WriteString(":{num_rpc:") | ||
builder.WriteString(strconv.FormatUint(uint64(s.Count), 10)) | ||
builder.WriteString(", total_time:") | ||
builder.WriteString(util.FormatDuration(s.Consume)) | ||
builder.WriteString("}") | ||
} | ||
|
||
// String implements fmt.Stringer interface. | ||
func (r *RequestErrorStats) String() string { | ||
if len(r.ErrStats) == 0 { | ||
|
@@ -242,7 +283,11 @@ func (r *RequestErrorStats) String() string { | |
// Clone returns a copy of itself. | ||
func (r *RegionRequestRuntimeStats) Clone() *RegionRequestRuntimeStats { | ||
newRs := NewRegionRequestRuntimeStats() | ||
maps.Copy(newRs.RPCStats, r.RPCStats) | ||
newRs.FirstRPCStats = r.FirstRPCStats | ||
if r.OtherRPCStatsMap != nil { | ||
newRs.OtherRPCStatsMap = make(map[tikvrpc.CmdType]*RPCRuntimeStats) | ||
maps.Copy(newRs.OtherRPCStatsMap, r.OtherRPCStatsMap) | ||
} | ||
if len(r.ErrStats) > 0 { | ||
newRs.ErrStats = make(map[string]int) | ||
maps.Copy(newRs.ErrStats, r.ErrStats) | ||
|
@@ -256,17 +301,11 @@ func (r *RegionRequestRuntimeStats) Merge(rs *RegionRequestRuntimeStats) { | |
if rs == nil { | ||
return | ||
} | ||
for cmd, v := range rs.RPCStats { | ||
stat, ok := r.RPCStats[cmd] | ||
if !ok { | ||
r.RPCStats[cmd] = &RPCRuntimeStats{ | ||
Count: v.Count, | ||
Consume: v.Consume, | ||
} | ||
continue | ||
} | ||
stat.Count += v.Count | ||
stat.Consume += v.Consume | ||
if rs.FirstRPCStats.Count > 0 { | ||
r.mergeRPCRuntimeStats(&rs.FirstRPCStats) | ||
} | ||
for _, v := range rs.OtherRPCStatsMap { | ||
r.mergeRPCRuntimeStats(v) | ||
} | ||
if len(rs.ErrStats) > 0 { | ||
if r.ErrStats == nil { | ||
|
@@ -279,6 +318,29 @@ func (r *RegionRequestRuntimeStats) Merge(rs *RegionRequestRuntimeStats) { | |
} | ||
} | ||
|
||
func (r *RegionRequestRuntimeStats) mergeRPCRuntimeStats(rs *RPCRuntimeStats) { | ||
if r.FirstRPCStats.Count == 0 || r.FirstRPCStats.Cmd == rs.Cmd { | ||
r.FirstRPCStats.Cmd = rs.Cmd | ||
r.FirstRPCStats.Count += rs.Count | ||
r.FirstRPCStats.Consume += rs.Consume | ||
return | ||
} | ||
if r.OtherRPCStatsMap == nil { | ||
r.OtherRPCStatsMap = make(map[tikvrpc.CmdType]*RPCRuntimeStats) | ||
} | ||
stat, ok := r.OtherRPCStatsMap[rs.Cmd] | ||
if !ok { | ||
r.OtherRPCStatsMap[rs.Cmd] = &RPCRuntimeStats{ | ||
Cmd: rs.Cmd, | ||
Count: rs.Count, | ||
Consume: rs.Consume, | ||
} | ||
return | ||
} | ||
stat.Count += rs.Count | ||
stat.Consume += rs.Consume | ||
} | ||
|
||
// ReplicaAccessStats records the replica access info. | ||
type ReplicaAccessStats struct { | ||
// AccessInfos records the access info | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why our own repo here? not offical pingcap/tidb? @cfzjywxk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to pass the CI test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After pingcap/tidb#58420 merged, #1540 will recover ci reference to original tidb.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@siddontang
The TiDB compatibility tests in
client-go
can be removed in the future. These tests make modifyingclient-go
very cumbersome after the repository split. In practice, updating theclient-go
dependency in TiDB already serves as a compatibility test.