91 lines
3.8 KiB
Go
91 lines
3.8 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package hack
|
|
|
|
import (
|
|
"runtime"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
// MutableString can be used as string via string(MutableString) without performance loss.
|
|
type MutableString string
|
|
|
|
// String converts slice to MutableString without copy.
|
|
// The MutableString can be converts to string without copy.
|
|
// Use it at your own risk.
|
|
func String(b []byte) MutableString {
|
|
if len(b) == 0 {
|
|
return ""
|
|
}
|
|
return MutableString(unsafe.String(unsafe.SliceData(b), len(b)))
|
|
}
|
|
|
|
// Slice converts string to slice without copy.
|
|
// Use at your own risk.
|
|
func Slice(s string) []byte {
|
|
return unsafe.Slice(unsafe.StringData(s), len(s))
|
|
}
|
|
|
|
// LoadFactor is the maximum average load of a bucket that triggers growth is 6.5 in Golang Map.
|
|
// Represent as LoadFactorNum/LoadFactorDen, to allow integer math.
|
|
// They are from the golang definition. ref: https://github.com/golang/go/blob/go1.13.15/src/runtime/map.go#L68-L71
|
|
const (
|
|
// LoadFactorDen is the denominator of load factor
|
|
LoadFactorDen = 2
|
|
)
|
|
|
|
// LoadFactorNum is the numerator of load factor
|
|
var LoadFactorNum = 13
|
|
|
|
func init() {
|
|
// In go1.21, the load factor num becomes 12 and go team has decided not to backport the fix to 1.21.
|
|
// See more details in https://github.com/golang/go/issues/63438
|
|
if strings.Contains(runtime.Version(), `go1.21`) || strings.Contains(runtime.Version(), `go1.22`) {
|
|
LoadFactorNum = 12
|
|
}
|
|
}
|
|
|
|
const (
|
|
// DefBucketMemoryUsageForMapStrToSlice = bucketSize*(1+unsafe.Sizeof(string) + unsafe.Sizeof(slice))+2*ptrSize
|
|
// ref https://github.com/golang/go/blob/go1.15.6/src/reflect/type.go#L2162.
|
|
// The bucket size may be changed by golang implement in the future.
|
|
// Golang Map needs to acquire double the memory when expanding,
|
|
// and the old buckets will be released after the data is migrated.
|
|
// Considering the worst case, the data in the old bucket cannot be migrated in time, and the old bucket cannot
|
|
// be GCed, we expand the bucket size to 1.5 times to estimate the memory usage of Golang Map.
|
|
DefBucketMemoryUsageForMapStrToSlice = (8*(1+16+24) + 16) / 2 * 3
|
|
// DefBucketMemoryUsageForMapIntToPtr = bucketSize*(1+unsafe.Sizeof(uint64) + unsafe.Sizeof(pointer))+2*ptrSize
|
|
DefBucketMemoryUsageForMapIntToPtr = (8*(1+8+8) + 16) / 2 * 3
|
|
// DefBucketMemoryUsageForMapStringToAny = bucketSize*(1+unsafe.Sizeof(string) + unsafe.Sizeof(interface{}))+2*ptrSize
|
|
DefBucketMemoryUsageForMapStringToAny = (8*(1+16+16) + 16) / 2 * 3
|
|
// DefBucketMemoryUsageForSetString = bucketSize*(1+unsafe.Sizeof(string) + unsafe.Sizeof(struct{}))+2*ptrSize
|
|
DefBucketMemoryUsageForSetString = (8*(1+16+0) + 16) / 2 * 3
|
|
// DefBucketMemoryUsageForSetFloat64 = bucketSize*(1+unsafe.Sizeof(float64) + unsafe.Sizeof(struct{}))+2*ptrSize
|
|
DefBucketMemoryUsageForSetFloat64 = (8*(1+8+0) + 16) / 2 * 3
|
|
// DefBucketMemoryUsageForSetInt64 = bucketSize*(1+unsafe.Sizeof(int64) + unsafe.Sizeof(struct{}))+2*ptrSize
|
|
DefBucketMemoryUsageForSetInt64 = (8*(1+8+0) + 16) / 2 * 3
|
|
)
|
|
|
|
// EstimateBucketMemoryUsage returns the estimated memory usage of a bucket in a map.
|
|
func EstimateBucketMemoryUsage[K comparable, V any]() uint64 {
|
|
return (8*(1+uint64(unsafe.Sizeof(*new(K))+unsafe.Sizeof(*new(V)))) + 16) / 2 * 3
|
|
}
|
|
|
|
// GetBytesFromPtr return a bytes array from the given ptr and length
|
|
func GetBytesFromPtr(ptr unsafe.Pointer, length int) []byte {
|
|
return unsafe.Slice((*byte)(ptr), length)
|
|
}
|