Commit 2b583157 authored by Chris Palmer's avatar Chris Palmer Committed by Commit Bot

Documentation tweaking for Partition Alloc.

A foolish consistency is the hobgoblin of little minds. #welp

Bug: None
Change-Id: Ia174e3fa99252a7931429c22d769872bc2f0c3bd
Reviewed-on: https://chromium-review.googlesource.com/c/1357625
Commit-Queue: Chris Palmer <palmer@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613253}
parent d80f1a22
...@@ -17,90 +17,106 @@ static const size_t kAllocationGranularity = sizeof(void*); ...@@ -17,90 +17,106 @@ static const size_t kAllocationGranularity = sizeof(void*);
static const size_t kAllocationGranularityMask = kAllocationGranularity - 1; static const size_t kAllocationGranularityMask = kAllocationGranularity - 1;
static const size_t kBucketShift = (kAllocationGranularity == 8) ? 3 : 2; static const size_t kBucketShift = (kAllocationGranularity == 8) ? 3 : 2;
// Underlying partition storage pages are a power-of-two size. It is typical // Underlying partition storage pages (`PartitionPage`s) are a power-of-2 size.
// for a partition page to be based on multiple system pages. Most references to // It is typical for a `PartitionPage` to be based on multiple system pages.
// "page" refer to partition pages. // Most references to "page" refer to `PartitionPage`s.
// We also have the concept of "super pages" -- these are the underlying system //
// allocations we make. Super pages contain multiple partition pages inside them // *Super pages* are the underlying system allocations we make. Super pages
// and include space for a small amount of metadata per partition page. // contain multiple partition pages and include space for a small amount of
// Inside super pages, we store "slot spans". A slot span is a continguous range // metadata per partition page.
// of one or more partition pages that stores allocations of the same size. //
// Inside super pages, we store *slot spans*. A slot span is a continguous range
// of one or more `PartitionPage`s that stores allocations of the same size.
// Slot span sizes are adjusted depending on the allocation size, to make sure // Slot span sizes are adjusted depending on the allocation size, to make sure
// the packing does not lead to unused (wasted) space at the end of the last // the packing does not lead to unused (wasted) space at the end of the last
// system page of the span. For our current max slot span size of 64k and other // system page of the span. For our current maximum slot span size of 64 KiB and
// constant values, we pack _all_ PartitionRootGeneric::Alloc() sizes perfectly // other constant values, we pack _all_ `PartitionRootGeneric::Alloc` sizes
// up against the end of a system page. // perfectly up against the end of a system page.
#if defined(_MIPS_ARCH_LOONGSON) #if defined(_MIPS_ARCH_LOONGSON)
static const size_t kPartitionPageShift = 16; // 64KB static const size_t kPartitionPageShift = 16; // 64 KiB
#else #else
static const size_t kPartitionPageShift = 14; // 16KB static const size_t kPartitionPageShift = 14; // 16 KiB
#endif #endif
static const size_t kPartitionPageSize = 1 << kPartitionPageShift; static const size_t kPartitionPageSize = 1 << kPartitionPageShift;
static const size_t kPartitionPageOffsetMask = kPartitionPageSize - 1; static const size_t kPartitionPageOffsetMask = kPartitionPageSize - 1;
static const size_t kPartitionPageBaseMask = ~kPartitionPageOffsetMask; static const size_t kPartitionPageBaseMask = ~kPartitionPageOffsetMask;
// TODO: Should this be 1 if defined(_MIPS_ARCH_LOONGSON)?
static const size_t kMaxPartitionPagesPerSlotSpan = 4; static const size_t kMaxPartitionPagesPerSlotSpan = 4;
// To avoid fragmentation via never-used freelist entries, we hand out partition // To avoid fragmentation via never-used freelist entries, we hand out partition
// freelist sections gradually, in units of the dominant system page size. // freelist sections gradually, in units of the dominant system page size. What
// What we're actually doing is avoiding filling the full partition page (16 KB) // we're actually doing is avoiding filling the full `PartitionPage` (16 KiB)
// with freelist pointers right away. Writing freelist pointers will fault and // with freelist pointers right away. Writing freelist pointers will fault and
// dirty a private page, which is very wasteful if we never actually store // dirty a private page, which is very wasteful if we never actually store
// objects there. // objects there.
static const size_t kNumSystemPagesPerPartitionPage = static const size_t kNumSystemPagesPerPartitionPage =
kPartitionPageSize / kSystemPageSize; kPartitionPageSize / kSystemPageSize;
static const size_t kMaxSystemPagesPerSlotSpan = static const size_t kMaxSystemPagesPerSlotSpan =
kNumSystemPagesPerPartitionPage * kMaxPartitionPagesPerSlotSpan; kNumSystemPagesPerPartitionPage * kMaxPartitionPagesPerSlotSpan;
// We reserve virtual address space in 2MB chunks (aligned to 2MB as well). // We reserve virtual address space in 2 MiB chunks (aligned to 2 MiB as well).
// These chunks are called "super pages". We do this so that we can store // These chunks are called *super pages*. We do this so that we can store
// metadata in the first few pages of each 2MB aligned section. This leads to // metadata in the first few pages of each 2 MiB-aligned section. This makes
// a very fast free(). We specifically choose 2MB because this virtual address // freeing memory very fast. We specifically choose 2 MiB because this virtual
// block represents a full but single PTE allocation on ARM, ia32 and x64. // address block represents a full but single PTE allocation on ARM, ia32 and
// x64.
// //
// The layout of the super page is as follows. The sizes below are the same // The layout of the super page is as follows. The sizes below are the same for
// for 32 bit and 64 bit. // 32- and 64-bit platforms.
// //
// | Guard page (4KB) | // +-----------------------+
// | Metadata page (4KB) | // | Guard page (4 KiB) |
// | Guard pages (8KB) | // | Metadata page (4 KiB) |
// | Guard pages (8 KiB) |
// | Slot span | // | Slot span |
// | Slot span | // | Slot span |
// | ... | // | ... |
// | Slot span | // | Slot span |
// | Guard page (4KB) | // | Guard page (4 KiB) |
// +-----------------------+
// //
// - Each slot span is a contiguous range of one or more PartitionPages. // Each slot span is a contiguous range of one or more `PartitionPage`s.
// - The metadata page has the following format. Note that the PartitionPage
// that is not at the head of a slot span is "unused". In other words,
// the metadata for the slot span is stored only in the first PartitionPage
// of the slot span. Metadata accesses to other PartitionPages are
// redirected to the first PartitionPage.
// //
// | SuperPageExtentEntry (32B) | // The metadata page has the following format. Note that the `PartitionPage`
// | PartitionPage of slot span 1 (32B, used) | // that is not at the head of a slot span is "unused". In other words, the
// | PartitionPage of slot span 1 (32B, unused) | // metadata for the slot span is stored only in the first `PartitionPage` of the
// | PartitionPage of slot span 1 (32B, unused) | // slot span. Metadata accesses to other `PartitionPage`s are redirected to the
// | PartitionPage of slot span 2 (32B, used) | // first `PartitionPage`.
// | PartitionPage of slot span 3 (32B, used) | //
// +---------------------------------------------+
// | SuperPageExtentEntry (32 B) |
// | PartitionPage of slot span 1 (32 B, used) |
// | PartitionPage of slot span 1 (32 B, unused) |
// | PartitionPage of slot span 1 (32 B, unused) |
// | PartitionPage of slot span 2 (32 B, used) |
// | PartitionPage of slot span 3 (32 B, used) |
// | ... | // | ... |
// | PartitionPage of slot span N (32B, unused) | // | PartitionPage of slot span N (32 B, unused) |
// +---------------------------------------------+
// //
// A direct mapped page has a similar layout to fake it looking like a super // A direct-mapped page has a similar layout to fake it looking like a super
// page: // page:
// //
// | Guard page (4KB) | // +-----------------------+
// | Metadata page (4KB) | // | Guard page (4 KiB) |
// | Guard pages (8KB) | // | Metadata page (4 KiB) |
// | Guard pages (8 KiB) |
// | Direct mapped object | // | Direct mapped object |
// | Guard page (4KB) | // | Guard page (4 KiB) |
// +-----------------------+
// //
// - The metadata page has the following layout: // A direct-mapped page's metadata page has the following layout:
// //
// | SuperPageExtentEntry (32B) | // +--------------------------------+
// | PartitionPage (32B) | // | SuperPageExtentEntry (32 B) |
// | PartitionBucket (32B) | // | PartitionPage (32 B) |
// | PartitionDirectMapExtent (8B) | // | PartitionBucket (32 B) |
static const size_t kSuperPageShift = 21; // 2MB // | PartitionDirectMapExtent (8 B) |
// +--------------------------------+
static const size_t kSuperPageShift = 21; // 2 MiB
static const size_t kSuperPageSize = 1 << kSuperPageShift; static const size_t kSuperPageSize = 1 << kSuperPageShift;
static const size_t kSuperPageOffsetMask = kSuperPageSize - 1; static const size_t kSuperPageOffsetMask = kSuperPageSize - 1;
static const size_t kSuperPageBaseMask = ~kSuperPageOffsetMask; static const size_t kSuperPageBaseMask = ~kSuperPageOffsetMask;
...@@ -108,15 +124,17 @@ static const size_t kNumPartitionPagesPerSuperPage = ...@@ -108,15 +124,17 @@ static const size_t kNumPartitionPagesPerSuperPage =
kSuperPageSize / kPartitionPageSize; kSuperPageSize / kPartitionPageSize;
// The following kGeneric* constants apply to the generic variants of the API. // The following kGeneric* constants apply to the generic variants of the API.
// The "order" of an allocation is closely related to the power-of-two size of // The "order" of an allocation is closely related to the power-of-1 size of the
// the allocation. More precisely, the order is the bit index of the // allocation. More precisely, the order is the bit index of the
// most-significant-bit in the allocation size, where the bit numbers starts // most-significant-bit in the allocation size, where the bit numbers starts at
// at index 1 for the least-significant-bit. // index 1 for the least-significant-bit.
//
// In terms of allocation sizes, order 0 covers 0, order 1 covers 1, order 2 // In terms of allocation sizes, order 0 covers 0, order 1 covers 1, order 2
// covers 2->3, order 3 covers 4->7, order 4 covers 8->15. // covers 2->3, order 3 covers 4->7, order 4 covers 8->15.
static const size_t kGenericMinBucketedOrder = 4; // 8 bytes. static const size_t kGenericMinBucketedOrder = 4; // 8 bytes.
static const size_t kGenericMaxBucketedOrder = // The largest bucketed order is 1 << (20 - 1), storing [512 KiB, 1 MiB):
20; // Largest bucketed order is 1<<(20-1) (storing 512KB -> almost 1MB) static const size_t kGenericMaxBucketedOrder = 20;
static const size_t kGenericNumBucketedOrders = static const size_t kGenericNumBucketedOrders =
(kGenericMaxBucketedOrder - kGenericMinBucketedOrder) + 1; (kGenericMaxBucketedOrder - kGenericMinBucketedOrder) + 1;
// Eight buckets per order (for the higher orders), e.g. order 8 is 128, 144, // Eight buckets per order (for the higher orders), e.g. order 8 is 128, 144,
...@@ -133,28 +151,27 @@ static const size_t kGenericMaxBucketSpacing = ...@@ -133,28 +151,27 @@ static const size_t kGenericMaxBucketSpacing =
static const size_t kGenericMaxBucketed = static const size_t kGenericMaxBucketed =
(1 << (kGenericMaxBucketedOrder - 1)) + (1 << (kGenericMaxBucketedOrder - 1)) +
((kGenericNumBucketsPerOrder - 1) * kGenericMaxBucketSpacing); ((kGenericNumBucketsPerOrder - 1) * kGenericMaxBucketSpacing);
static const size_t kGenericMinDirectMappedDownsize = // Limit when downsizing a direct mapping using `realloc`:
kGenericMaxBucketed + static const size_t kGenericMinDirectMappedDownsize = kGenericMaxBucketed + 1;
1; // Limit when downsizing a direct mapping using realloc().
static const size_t kGenericMaxDirectMapped = static const size_t kGenericMaxDirectMapped =
(1UL << 31) + kPageAllocationGranularity; // 2 GB plus one more page. (1UL << 31) + kPageAllocationGranularity; // 2 GiB plus 1 more page.
static const size_t kBitsPerSizeT = sizeof(void*) * CHAR_BIT; static const size_t kBitsPerSizeT = sizeof(void*) * CHAR_BIT;
// Constant for the memory reclaim logic. // Constant for the memory reclaim logic.
static const size_t kMaxFreeableSpans = 16; static const size_t kMaxFreeableSpans = 16;
// If the total size in bytes of allocated but not committed pages exceeds this // If the total size in bytes of allocated but not committed pages exceeds this
// value (probably it is a "out of virtual address space" crash), // value (probably it is a "out of virtual address space" crash), a special
// a special crash stack trace is generated at |PartitionOutOfMemory|. // crash stack trace is generated at
// This is to distinguish "out of virtual address space" from // `PartitionOutOfMemoryWithLotsOfUncommitedPages`. This is to distinguish "out
// "out of physical memory" in crash reports. // of virtual address space" from "out of physical memory" in crash reports.
static const size_t kReasonableSizeOfUnusedPages = 1024 * 1024 * 1024; // 1GB static const size_t kReasonableSizeOfUnusedPages = 1024 * 1024 * 1024; // 1 GiB
// These two byte values match tcmalloc. // These byte values match tcmalloc.
static const unsigned char kUninitializedByte = 0xAB; static const unsigned char kUninitializedByte = 0xAB;
static const unsigned char kFreedByte = 0xCD; static const unsigned char kFreedByte = 0xCD;
// Flags for PartitionAllocGenericFlags. // Flags for `PartitionAllocGenericFlags`.
enum PartitionAllocFlags { enum PartitionAllocFlags {
PartitionAllocReturnNull = 1 << 0, PartitionAllocReturnNull = 1 << 0,
PartitionAllocZeroFill = 1 << 1, PartitionAllocZeroFill = 1 << 1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment