-
Notifications
You must be signed in to change notification settings - Fork 450
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds a breakdown of cgo memory usage in Pebble. This will show up as part of the periodic LSM metrics dump in the logs.
- Loading branch information
1 parent
c8c3806
commit fc6eab0
Showing
17 changed files
with
197 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,63 @@ | ||
// Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use | ||
// Copyright 2024 The LevelDB-Go and Pebble Authors. All rights reserved. Use | ||
// of this source code is governed by a BSD-style license that can be found in | ||
// the LICENSE file. | ||
|
||
package manual | ||
|
||
// #include <stdlib.h> | ||
import "C" | ||
import "unsafe" | ||
import ( | ||
"fmt" | ||
"sync/atomic" | ||
|
||
// The go:linkname directives provides backdoor access to private functions in | ||
// the runtime. Below we're accessing the throw function. | ||
"github.com/cockroachdb/pebble/internal/invariants" | ||
) | ||
|
||
//go:linkname throw runtime.throw | ||
func throw(s string) | ||
// Purpose identifies the use-case for an allocation. | ||
type Purpose uint8 | ||
|
||
// TODO(peter): Rather than relying an C malloc/free, we could fork the Go | ||
// runtime page allocator and allocate large chunks of memory using mmap or | ||
// similar. | ||
const ( | ||
_ Purpose = iota | ||
|
||
// New allocates a slice of size n. The returned slice is from manually managed | ||
// memory and MUST be released by calling Free. Failure to do so will result in | ||
// a memory leak. | ||
func New(n int) []byte { | ||
if n == 0 { | ||
return make([]byte, 0) | ||
} | ||
// We need to be conscious of the Cgo pointer passing rules: | ||
// | ||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers | ||
// | ||
// ... | ||
// Note: the current implementation has a bug. While Go code is permitted | ||
// to write nil or a C pointer (but not a Go pointer) to C memory, the | ||
// current implementation may sometimes cause a runtime error if the | ||
// contents of the C memory appear to be a Go pointer. Therefore, avoid | ||
// passing uninitialized C memory to Go code if the Go code is going to | ||
// store pointer values in it. Zero out the memory in C before passing it | ||
// to Go. | ||
ptr := C.calloc(C.size_t(n), 1) | ||
if ptr == nil { | ||
// NB: throw is like panic, except it guarantees the process will be | ||
// terminated. The call below is exactly what the Go runtime invokes when | ||
// it cannot allocate memory. | ||
throw("out of memory") | ||
BlockCacheMap | ||
BlockCacheEntry | ||
BlockCacheData | ||
MemTable | ||
|
||
NumPurposes | ||
) | ||
|
||
// Metrics contains memory statistics by purpose. | ||
type Metrics [NumPurposes]struct { | ||
// InUseBytes is the total number of bytes currently allocated. This is just | ||
// the sum of the lengths of the allocations and does not include any overhead | ||
// or fragmentation. | ||
InUseBytes uint64 | ||
} | ||
|
||
var counters [NumPurposes]struct { | ||
InUseBytes atomic.Int64 | ||
// Pad to separate counters into cache lines. This reduces the overhead when | ||
// multiple purposes are used frequently. We assume 64 byte cache line size | ||
// which is the case for ARM64 servers and AMD64. | ||
_ [7]uint64 | ||
} | ||
|
||
func recordAlloc(purpose Purpose, n int) { | ||
counters[purpose].InUseBytes.Add(int64(n)) | ||
} | ||
|
||
func recordFree(purpose Purpose, n int) { | ||
newVal := counters[purpose].InUseBytes.Add(-int64(n)) | ||
if invariants.Enabled && newVal < 0 { | ||
panic(fmt.Sprintf("negative counter value %d", newVal)) | ||
} | ||
// Interpret the C pointer as a pointer to a Go array, then slice. | ||
return (*[MaxArrayLen]byte)(unsafe.Pointer(ptr))[:n:n] | ||
} | ||
|
||
// Free frees the specified slice. | ||
func Free(b []byte) { | ||
if cap(b) != 0 { | ||
if len(b) == 0 { | ||
b = b[:cap(b)] | ||
} | ||
ptr := unsafe.Pointer(&b[0]) | ||
C.free(ptr) | ||
// GetMetrics returns manual memory usage statistics. | ||
func GetMetrics() Metrics { | ||
var res Metrics | ||
for i := range res { | ||
// We load the freed count first to avoid a negative value, since we don't load both counters atomically. | ||
res[i].InUseBytes = uint64(counters[i].InUseBytes.Load()) | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use | ||
// of this source code is governed by a BSD-style license that can be found in | ||
// the LICENSE file. | ||
|
||
package manual | ||
|
||
// #include <stdlib.h> | ||
import "C" | ||
import "unsafe" | ||
|
||
// The go:linkname directives provides backdoor access to private functions in | ||
// the runtime. Below we're accessing the throw function. | ||
|
||
//go:linkname throw runtime.throw | ||
func throw(s string) | ||
|
||
// TODO(peter): Rather than relying an C malloc/free, we could fork the Go | ||
// runtime page allocator and allocate large chunks of memory using mmap or | ||
// similar. | ||
|
||
// New allocates a slice of size n. The returned slice is from manually managed | ||
// memory and MUST be released by calling Free. Failure to do so will result in | ||
// a memory leak. | ||
func New(purpose Purpose, n int) []byte { | ||
if n == 0 { | ||
return make([]byte, 0) | ||
} | ||
recordAlloc(purpose, n) | ||
// We need to be conscious of the Cgo pointer passing rules: | ||
// | ||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers | ||
// | ||
// ... | ||
// Note: the current implementation has a bug. While Go code is permitted | ||
// to write nil or a C pointer (but not a Go pointer) to C memory, the | ||
// current implementation may sometimes cause a runtime error if the | ||
// contents of the C memory appear to be a Go pointer. Therefore, avoid | ||
// passing uninitialized C memory to Go code if the Go code is going to | ||
// store pointer values in it. Zero out the memory in C before passing it | ||
// to Go. | ||
ptr := C.calloc(C.size_t(n), 1) | ||
if ptr == nil { | ||
// NB: throw is like panic, except it guarantees the process will be | ||
// terminated. The call below is exactly what the Go runtime invokes when | ||
// it cannot allocate memory. | ||
throw("out of memory") | ||
} | ||
// Interpret the C pointer as a pointer to a Go array, then slice. | ||
return (*[MaxArrayLen]byte)(unsafe.Pointer(ptr))[:n:n] | ||
} | ||
|
||
// Free frees the specified slice. It has to be exactly the slice that was | ||
// returned by New. | ||
func Free(purpose Purpose, b []byte) { | ||
if cap(b) != 0 { | ||
recordFree(purpose, cap(b)) | ||
if len(b) == 0 { | ||
b = b[:cap(b)] | ||
} | ||
ptr := unsafe.Pointer(&b[0]) | ||
C.free(ptr) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.