Skip to content
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

executor: support tidb memory debug mode #35322

Merged
merged 27 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4d356ab
memory debug mode
wshwsh12 Apr 27, 2022
c2fa0e2
debug debug mode
wshwsh12 Jun 1, 2022
9b1dc4f
log all tracker
wshwsh12 Jun 6, 2022
223c8fc
format
wshwsh12 Jun 6, 2022
8a3d5a0
Merge remote-tracking branch 'upstream/master' into tidb_memory_debug…
wshwsh12 Jun 13, 2022
cd4399b
fmt
wshwsh12 Jun 13, 2022
ff6b1ef
Merge remote-tracking branch 'upstream/master' into tidb_memory_debug…
wshwsh12 Jul 7, 2022
2765c9b
Merge remote-tracking branch 'upstream/master' into tidb_memory_debug…
wshwsh12 Jul 8, 2022
3ca8663
address comments
wshwsh12 Jul 8, 2022
249055c
fix test
wshwsh12 Jul 8, 2022
0acd1dd
Merge remote-tracking branch 'upstream/master' into tidb_memory_debug…
wshwsh12 Jul 11, 2022
0326579
add comments
wshwsh12 Jul 11, 2022
e36f194
error
wshwsh12 Jul 11, 2022
6363022
address comments
wshwsh12 Jul 11, 2022
9c8adfc
Merge branch 'master' into tidb_memory_debug_mode
wshwsh12 Jul 11, 2022
2891647
address comments
wshwsh12 Jul 12, 2022
3ebb617
test default value
wshwsh12 Jul 12, 2022
38b7569
fix
wshwsh12 Jul 12, 2022
f26bce9
polish
XuHuaiyu Jul 12, 2022
153f29a
Merge remote-tracking branch 'xhy/tidb_memory_debug_mode' into tidb_m…
wshwsh12 Jul 12, 2022
0dee399
fmt
wshwsh12 Jul 12, 2022
4ca5878
fix
wshwsh12 Jul 12, 2022
6b16b72
polish
wshwsh12 Jul 12, 2022
3ebd6af
Merge branch 'master' into tidb_memory_debug_mode
wshwsh12 Jul 12, 2022
7c40a38
Merge branch 'master' into tidb_memory_debug_mode
wshwsh12 Jul 13, 2022
9b9c949
Merge branch 'master' into tidb_memory_debug_mode
ti-chi-bot Jul 13, 2022
b20f342
Merge branch 'master' into tidb_memory_debug_mode
ti-chi-bot Jul 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion executor/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,21 @@ package executor

import (
"context"
"go.uber.org/zap"
"os"
"path/filepath"
"runtime"
rpprof "runtime/pprof"
"strconv"
"time"

"github.com/cznic/mathutil"
"github.com/pingcap/errors"
"github.com/pingcap/tidb/config"
"github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/mathutil"
"github.com/pingcap/tidb/util/logutil"
"github.com/pingcap/tidb/util/memory"
)

// ExplainExec represents an explain executor.
Expand Down Expand Up @@ -89,6 +99,16 @@ func (e *ExplainExec) executeAnalyzeExec(ctx context.Context) (err error) {
}
}
}()
if e.ctx.GetSessionVars().MemoryDebugMode > 0 {
exit := make(chan bool)
e.runMemoryDebugGoroutine(exit)
defer func() {
select {
case <-exit:
}
}()
defer func() { exit <- false }()
}
e.executed = true
chk := newFirstChunk(e.analyzeExec)
for {
Expand Down Expand Up @@ -123,3 +143,86 @@ func (e *ExplainExec) getAnalyzeExecToExecutedNoDelay() Executor {
}
return nil
}

func (e *ExplainExec) runMemoryDebugGoroutine(exit chan bool) {
debugMode := e.ctx.GetSessionVars().MemoryDebugMode
ticker := time.NewTicker(5 * time.Second)
tracker := e.ctx.GetSessionVars().StmtCtx.MemTracker
instanceStats := &runtime.MemStats{}
var heapInUse, trackedMem uint64
const GB = 1024 * 1024 * 1024
go func() {
defer func() {
runtime.GC()
runtime.ReadMemStats(instanceStats)
heapInUse = instanceStats.HeapInuse
trackedMem = uint64(tracker.BytesConsumed())
logutil.BgLogger().Warn("Memory Debug Mode",
zap.String("sql", "finished"),
zap.String("heap in use", memory.FormatBytes(int64(heapInUse))),
zap.String("tracked memory", memory.FormatBytes(int64(trackedMem))),
zap.String("heap profile", e.getHeapProfile(false)))
close(exit)
}()
times := 0
for {
select {
case <-exit:
return
case <-ticker.C:
if debugMode == 2 {
runtime.GC()
}
runtime.ReadMemStats(instanceStats)
heapInUse = instanceStats.HeapInuse
trackedMem = uint64(tracker.BytesConsumed())

times++
if times%6 == 0 {
logutil.BgLogger().Warn("Memory Debug Mode",
zap.String("sql", "running"),
zap.String("heap in use", memory.FormatBytes(int64(heapInUse))),
zap.String("tracked memory", memory.FormatBytes(int64(trackedMem))))
}

if debugMode == 1 {
if heapInUse > 10*GB && trackedMem/10*15 < heapInUse {
logutil.BgLogger().Warn("Memory Debug Mode",
zap.String("debug mode 1 alarm", "trackedMem * 150% < heapInUse, maybe some allocation and free frequently"),
zap.String("heap in use", memory.FormatBytes(int64(heapInUse))),
zap.String("tracked memory", memory.FormatBytes(int64(trackedMem))),
zap.String("heap profile", e.getHeapProfile(true)))
}
} else {
if heapInUse > 10*GB && trackedMem/10*11 < heapInUse {
logutil.BgLogger().Warn("Memory Debug Mode",
zap.String("debug mode 2 alarm", "trackedMem * 110% < heapInUse after GC, maybe some memory not be tracked"),
zap.String("heap in use", memory.FormatBytes(int64(heapInUse))),
zap.String("tracked memory", memory.FormatBytes(int64(trackedMem))),
zap.String("heap profile", e.getHeapProfile(false)))
ts := tracker.SearchTrackerConsumedMoreThanNBytes(GB)
logs := make([]zap.Field, 0, len(ts))
for _, t := range ts {
logs = append(logs, zap.String("Executor_"+strconv.Itoa(t.Label()), memory.FormatBytes(t.BytesConsumed())))
}
logutil.BgLogger().Warn("Memory Debug Mode, Log all trackers that consumes more than 1GB", logs...)
}
}
}
}
}()
}

func (e *ExplainExec) getHeapProfile(gc bool) (fileName string) {
tempDir := filepath.Join(config.GetGlobalConfig().TempStoragePath, "record")
timeString := time.Now().Format(time.RFC3339)
if gc {
runtime.GC()
}
fileName = filepath.Join(tempDir, "heapGC"+timeString)
f, _ := os.Create(fileName)
p := rpprof.Lookup("heap")
_ = p.WriteTo(f, 0)
_ = f.Close()
return fileName
}
5 changes: 5 additions & 0 deletions planner/core/common_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,11 @@ func (e *Explain) RenderResult() error {
if err != nil {
return err
}
if e.Analyze {
row := e.Rows[0]
tracker := e.SCtx().GetSessionVars().StmtCtx.MemTracker
row[7] = row[7] + "(Total: " + tracker.FormatBytes(tracker.MaxConsumed()) + ")"
}
}
case types.ExplainFormatDOT:
if physicalPlan, ok := e.TargetPlan.(PhysicalPlan); ok {
Expand Down
3 changes: 3 additions & 0 deletions sessionctx/variable/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,9 @@ type SessionVars struct {

// MaxAllowedPacket indicates the maximum size of a packet for the MySQL protocol.
MaxAllowedPacket uint64

// MemoryDebugMode indicated the memory debug mode.
MemoryDebugMode int64
}

// InitStatementContext initializes a StatementContext, the object is reused to reduce allocation.
Expand Down
4 changes: 4 additions & 0 deletions sessionctx/variable/sysvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,10 @@ var defaultSysVars = []*SysVar{
metrics.ToggleSimplifiedMode(TiDBOptOn(s))
return nil
}},
{Scope: ScopeSession, Name: TiDBMemoryDebugMode, Value: strconv.Itoa(0), Type: TypeInt, MinValue: 0, MaxValue: 2, SetSession: func(s *SessionVars, val string) error {
s.MemoryDebugMode = TidbOptInt64(val, 0)
return nil
}},
}

// FeedbackProbability points to the FeedbackProbability in statistics package.
Expand Down
3 changes: 3 additions & 0 deletions sessionctx/variable/tidb_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,9 @@ const (

// TiDBSimplifiedMetrics controls whether to unregister some unused metrics.
TiDBSimplifiedMetrics = "tidb_simplified_metrics"

// TiDBMemoryDebugMode is used to set tidb memory debug mode.
TiDBMemoryDebugMode = "tidb_memory_debug_mode"
)

// TiDB vars that have only global scope
Expand Down
14 changes: 14 additions & 0 deletions util/memory/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,20 @@ func (t *Tracker) SearchTrackerWithoutLock(label int) *Tracker {
return nil
}

// SearchTrackerConsumedMoreThanNBytes searches the specific tracker that consumes more than NBytes.
func (t *Tracker) SearchTrackerConsumedMoreThanNBytes(limit int64) (res []*Tracker) {
t.mu.Lock()
defer t.mu.Unlock()
for _, sli := range t.mu.children {
for _, tracker := range sli {
if tracker.BytesConsumed() > limit {
res = append(res, tracker)
}
}
}
return
}

// String returns the string representation of this Tracker tree.
func (t *Tracker) String() string {
buffer := bytes.NewBufferString("\n")
Expand Down