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: make memory tracker for aggregate more accurate. #22463

Merged
merged 18 commits into from
Feb 18, 2021

Conversation

wshwsh12
Copy link
Contributor

@wshwsh12 wshwsh12 commented Jan 21, 2021

What problem does this PR solve?

Issue Number: close #22462

Problem Summary:

What is changed and how it works?

Proposal: xxx

What's Changed:

  1. Estimate the memory usage of aggPartialResultMapper and track it
  2. Track memory usage of HashAggFinalWorker.
  3. Track memory usage of GroupKey

How it Works:

Related changes

Check List

Tests

  • Manual test (add detailed scripts or steps below)

Side effects

  • Performance regression
    • Consumes more CPU
    • Consumes more MEM

Release note

  • No release note

@wshwsh12 wshwsh12 requested a review from a team as a code owner January 21, 2021 02:47
@wshwsh12 wshwsh12 requested review from lzmhhh123 and removed request for a team January 21, 2021 02:47
@github-actions github-actions bot added the sig/execution SIG execution label Jan 21, 2021
@wshwsh12 wshwsh12 removed the request for review from lzmhhh123 January 21, 2021 03:13
@wshwsh12 wshwsh12 changed the title executor: estimate the memory usage of aggPartialResultMapper executor: make memory tracker for aggregate more accurate. Jan 24, 2021
@wshwsh12
Copy link
Contributor Author

/run-all-tests

@XuHuaiyu XuHuaiyu added the type/enhancement The issue or PR belongs to an enhancement. label Jan 26, 2021
@wshwsh12
Copy link
Contributor Author

wshwsh12 commented Jan 28, 2021

Benchmark result: Benchmark tracks all memory allocation, but doesn't minus GC memory. So in this cases, Map memory use will be 2 times.

BenchmarkAggPartialResultMapperMemoryUsage/MapRows_0
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_0-16         	12869766	        98.7 ns/op	      80 B/op	       1 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_100
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_100-16       	   76569	     15660 ns/op	   12269 B/op	       9 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_10000
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_10000-16     	     507	   2341705 ns/op	 1611640 B/op	   10148 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_1000000
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_1000000-16   	       3	 346488865 ns/op	208428346 B/op	 1038292 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_851968
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_851968-16    	       5	 220406375 ns/op	113606825 B/op	  890112 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_851969
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_851969-16    	       5	 242470491 ns/op	207222587 B/op	  890200 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_425984
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_425984-16    	      10	 108088523 ns/op	56673632 B/op	  445000 allocs/op
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_425985
BenchmarkAggPartialResultMapperMemoryUsage/MapRows_425985-16    	       9	 119479831 ns/op	103461026 B/op	  444987 allocs/op

For example: When rownum is 1000000, B will be 18, and the estimated memory is (1<<18)*344 = 90177536B. In benchmark result, the result is 208428346B.

@@ -51,15 +51,32 @@ type baseHashAggWorker struct {
aggFuncs []aggfuncs.AggFunc
maxChunkSize int
stats *AggWorkerStat

memTracker *memory.Tracker
BInMap *int // incident B in Go map
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really hard to understand for the reader who does not know the implementation of Map.
We need a more detailed comment

executor/aggregate.go Outdated Show resolved Hide resolved
// defBucketMemoryUsage = bucketSize*(1+unsafe.Sizeof(string) + unsafe.Sizeof(slice))+2*ptrSize
defBucketMemoryUsage = 8*(1+16+24) + 16
// Maximum average load of a bucket that triggers growth is 6.5.
// Represent as loadFactorNum/loadFactorDen, to allow integer math.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need allow integer math?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use 6.5 directly, golang complier will throw an error constant 6.5 truncated to integer in the condition len(mapper) > (1<<*w.BInMap)*loadFactorNum/loadFactorDen.
If we want it run, maybe we need add some type conversions, eg float64(len(mapper)) > float64(int(1<<*w.BInMap))*6.5. I think it is inefficient.

executor/aggregate.go Outdated Show resolved Hide resolved
executor/aggregate.go Outdated Show resolved Hide resolved
executor/executor_pkg_test.go Show resolved Hide resolved
executor/benchmark_test.go Outdated Show resolved Hide resolved
const (
// ref https://github.com/golang/go/blob/go1.15.6/src/reflect/type.go#L2162.
// defBucketMemoryUsage = bucketSize*(1+unsafe.Sizeof(string) + unsafe.Sizeof(slice))+2*ptrSize
defBucketMemoryUsage = 8*(1+16+24) + 16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the bucket size changed by golang in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for curious, is there any way to set it dynamically according to different golang version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can check runtime.Version() to distinguish different Golang version, and using different estimation way. But we need to implement the estimation way for every different Golang version. (Of course, major version is enough).
Now Golang 1.13,1.14.1.15,1.16 uses the same map implement, so I think now we don't need to distinguish them.

executor/aggregate.go Outdated Show resolved Hide resolved
executor/aggregate.go Show resolved Hide resolved
Copy link
Contributor

@XuHuaiyu XuHuaiyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ti-srebot ti-srebot added the status/LGT1 Indicates that a PR has LGTM 1. label Feb 5, 2021
Copy link
Contributor

@lzmhhh123 lzmhhh123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ti-srebot ti-srebot removed the status/LGT1 Indicates that a PR has LGTM 1. label Feb 18, 2021
@ti-srebot ti-srebot added the status/LGT2 Indicates that a PR has LGTM 2. label Feb 18, 2021
@lzmhhh123
Copy link
Contributor

/merge

@ti-srebot ti-srebot added the status/can-merge Indicates a PR has been approved by a committer. label Feb 18, 2021
@ti-srebot
Copy link
Contributor

/run-all-tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sig/execution SIG execution status/can-merge Indicates a PR has been approved by a committer. status/LGT2 Indicates that a PR has LGTM 2. type/enhancement The issue or PR belongs to an enhancement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make memory tracker for aggregate more accurate.
4 participants