Skip to content

Commit

Permalink
Share common logic in SweepHeapSectioning base class
Browse files Browse the repository at this point in the history
Avoid logic duplication between SweepHeapSectioning subclasses

Signed-off-by: Lin Hu <linhu@ca.ibm.com>
  • Loading branch information
LinHu2016 committed Jul 1, 2021
1 parent ec902f6 commit 6ffedb9
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 116 deletions.
121 changes: 120 additions & 1 deletion gc/base/SweepHeapSectioning.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2015 IBM Corp. and others
* Copyright (c) 1991, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -31,6 +31,14 @@
#include "ParallelSweepChunk.hpp"
#include "SweepHeapSectioning.hpp"

#include "Heap.hpp"
#include "HeapRegionManager.hpp"
#include "MemoryPool.hpp"
#include "HeapRegionIterator.hpp"
#include "HeapRegionDescriptor.hpp"
#include "SweepPoolManager.hpp"
#include "ParallelDispatcher.hpp"

/**
* Internal storage memory pool for heap sectioning chunks.
*
Expand Down Expand Up @@ -339,3 +347,114 @@ MM_SweepHeapSectioning::getBackingStoreSize()
{
return _baseArray->_used * sizeof(MM_ParallelSweepChunk);
}

/**
* Return the expected total sweep chunks that will be used in the system.
* Called during initialization, this routine looks at the maximum size of the heap and expected
* configuration (generations, regions, etc) and determines the approximate maximum number of chunks
* that will be required for a sweep at any given time. It is safe to underestimate the number of chunks,
* as the sweep sectioning mechanism will compensate, but the expectation is that by having all
* chunk memory allocated in one go will keep the data localized and fragment system memory less.
* @return estimated upper bound number of chunks that will be required by the system.
*/
uintptr_t
MM_SweepHeapSectioning::estimateTotalChunkCount(MM_EnvironmentBase *env)
{
uintptr_t totalChunkCountEstimate;

if(0 == _extensions->parSweepChunkSize) {
/* -Xgc:sweepchunksize= has NOT been specified, so we set it heuristically.
*
* maxheapsize
* chunksize = ---------------- (rounded up to the nearest 256k)
* threadcount * 32
*/
_extensions->parSweepChunkSize = MM_Math::roundToCeiling(256*1024, _extensions->heap->getMaximumMemorySize() / (_extensions->dispatcher->threadCountMaximum() * 32));
}

totalChunkCountEstimate = MM_Math::roundToCeiling(_extensions->parSweepChunkSize, _extensions->heap->getMaximumMemorySize()) / _extensions->parSweepChunkSize;

return totalChunkCountEstimate;
}

uintptr_t
MM_SweepHeapSectioning::reassignChunks(MM_EnvironmentBase *env)
{
MM_ParallelSweepChunk *chunk; /* Sweep table chunk (global) */
MM_ParallelSweepChunk *previousChunk = NULL;
uintptr_t totalChunkCount = 0; /* Total chunks in system */

MM_SweepHeapSectioningIterator sectioningIterator(this);

MM_HeapRegionManager *regionManager = _extensions->getHeap()->getHeapRegionManager();
GC_HeapRegionIterator regionIterator(regionManager);
MM_HeapRegionDescriptor *region = NULL;

while (NULL != (region = regionIterator.nextRegion())) {
if (isReadyToSweep(env, region)) {
uintptr_t *heapChunkBase = (uintptr_t *)region->getLowAddress(); /* Heap chunk base pointer */
uintptr_t *regionHighAddress = (uintptr_t *)region->getHighAddress();

while (heapChunkBase < regionHighAddress) {
void *poolHighAddr = NULL;
uintptr_t *heapChunkTop = NULL;

chunk = sectioningIterator.nextChunk();
Assert_MM_true(chunk != NULL); /* Should never return NULL */
totalChunkCount += 1;

/* Clear all data in the chunk (including sweep implementation specific information) */
chunk->clear();

if(((uintptr_t)regionHighAddress - (uintptr_t)heapChunkBase) < _extensions->parSweepChunkSize) {
/* corner case - we will wrap our address range */
heapChunkTop = regionHighAddress;
} else {
/* normal case - just increment by the chunk size */
heapChunkTop = (uintptr_t *)((uintptr_t)heapChunkBase + _extensions->parSweepChunkSize);
}

/* Find out if the range of memory we are considering spans 2 different pools. If it does,
* the current chunk can only be attributed to one, so we limit the upper range of the chunk
* to the first pool and will continue the assignment at the upper address range.
*/
MM_MemoryPool *pool = region->getSubSpace()->getMemoryPool(env, heapChunkBase, heapChunkTop, poolHighAddr);
if (NULL == poolHighAddr) {
heapChunkTop = (heapChunkTop > regionHighAddress ? regionHighAddress : heapChunkTop);
} else {
/* Yes ..so adjust chunk boundaries */
Assert_MM_true(poolHighAddr > heapChunkBase && poolHighAddr < heapChunkTop);
heapChunkTop = (uintptr_t *) poolHighAddr;
}

/* All values for the chunk have been calculated - assign them */
chunk->chunkBase = (void *)heapChunkBase;
chunk->chunkTop = (void *)heapChunkTop;
chunk->memoryPool = pool;
Assert_MM_true(NULL != pool);
/* Some memory pools, like the one in LOA, may have larger min free size then in the rest of the heap being swept */
chunk->_minFreeSize = OMR_MAX(pool->getMinimumFreeEntrySize(), pool->getSweepPoolManager()->getMinimumFreeSize());

chunk->_coalesceCandidate = (heapChunkBase != region->getLowAddress());
chunk->_previous= previousChunk;
if(NULL != previousChunk) {
previousChunk->_next = chunk;
}

/* Move to the next chunk */
heapChunkBase = heapChunkTop;

/* and remember address of previous chunk */
previousChunk = chunk;

Assert_MM_true((uintptr_t)heapChunkBase == MM_Math::roundToCeiling(_extensions->heapAlignment,(uintptr_t)heapChunkBase));
}
}
}

if(NULL != previousChunk) {
previousChunk->_next = NULL;
}

return totalChunkCount;
}
8 changes: 5 additions & 3 deletions gc/base/SweepHeapSectioning.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2015 IBM Corp. and others
* Copyright (c) 1991, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -31,6 +31,7 @@

class MM_ParallelSweepChunk;
class MM_ParallelSweepChunkArray;
class MM_HeapRegionDescriptor;

/**
* Support for sectioning the heap into chunks useable by sweep (and compact).
Expand All @@ -50,8 +51,9 @@ class MM_SweepHeapSectioning : public MM_BaseVirtual {
virtual bool initialize(MM_EnvironmentBase* env);
void tearDown(MM_EnvironmentBase* env);

virtual uintptr_t estimateTotalChunkCount(MM_EnvironmentBase* env) = 0;
virtual uintptr_t estimateTotalChunkCount(MM_EnvironmentBase* env);
virtual uintptr_t calculateActualChunkNumbers() const = 0;
virtual bool isReadyToSweep(MM_EnvironmentBase* env, MM_HeapRegionDescriptor* region) { return false; }

bool initArrays(uintptr_t);

Expand All @@ -61,7 +63,7 @@ class MM_SweepHeapSectioning : public MM_BaseVirtual {
virtual void kill(MM_EnvironmentBase* env);

bool update(MM_EnvironmentBase* env);
virtual uintptr_t reassignChunks(MM_EnvironmentBase* env) = 0;
virtual uintptr_t reassignChunks(MM_EnvironmentBase* env);

void* getBackingStoreAddress();
uintptr_t getBackingStoreSize();
Expand Down
110 changes: 1 addition & 109 deletions gc/base/standard/SweepHeapSectioningSegmented.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include "EnvironmentBase.hpp"
#include "Heap.hpp"
#include "HeapRegionIterator.hpp"
#include "HeapRegionDescriptor.hpp"
#include "NonVirtualMemory.hpp"
#include "MemoryPool.hpp"
#include "MemorySubSpace.hpp"
Expand All @@ -48,19 +47,7 @@
uintptr_t
MM_SweepHeapSectioningSegmented::estimateTotalChunkCount(MM_EnvironmentBase *env)
{
uintptr_t totalChunkCountEstimate;

if(0 == _extensions->parSweepChunkSize) {
/* -Xgc:sweepchunksize= has NOT been specified, so we set it heuristically.
*
* maxheapsize
* chunksize = ---------------- (rounded up to the nearest 256k)
* threadcount * 32
*/
_extensions->parSweepChunkSize = MM_Math::roundToCeiling(256*1024, _extensions->heap->getMaximumMemorySize() / (_extensions->dispatcher->threadCountMaximum() * 32));
}

totalChunkCountEstimate = MM_Math::roundToCeiling(_extensions->parSweepChunkSize, _extensions->heap->getMaximumMemorySize()) / _extensions->parSweepChunkSize;
uintptr_t totalChunkCountEstimate = MM_SweepHeapSectioning::estimateTotalChunkCount(env);

#if defined(OMR_GC_MODRON_SCAVENGER)
/* Because object memory segments have not been allocated yet, we cannot get the real numbers.
Expand Down Expand Up @@ -109,101 +96,6 @@ MM_SweepHeapSectioningSegmented::calculateActualChunkNumbers() const
return totalChunkCount;
}

/**
* Reset and reassign each chunk to a range of heap memory.
* Given the current updated listed of chunks and the corresponding heap memory, walk the chunk
* list reassigning each chunk to an appropriate range of memory. This will clear each chunk
* structure and then assign its basic values that connect it to a range of memory (base/top,
* pool, segment, etc).
* @return the total number of chunks in the system.
*/
uintptr_t
MM_SweepHeapSectioningSegmented::reassignChunks(MM_EnvironmentBase *env)
{
MM_ParallelSweepChunk *chunk; /* Sweep table chunk (global) */
MM_ParallelSweepChunk *previousChunk;
uintptr_t totalChunkCount; /* Total chunks in system */

MM_SweepHeapSectioningIterator sectioningIterator(this);

totalChunkCount = 0;
previousChunk = NULL;

MM_HeapRegionManager *regionManager = _extensions->getHeap()->getHeapRegionManager();
GC_HeapRegionIterator regionIterator(regionManager);
MM_HeapRegionDescriptor *region = NULL;

while (NULL != (region = regionIterator.nextRegion())) {
if (region->isCommitted()) {
/* TODO: this must be rethought for Tarok since it treats all regions identically but some might require different sweep logic */
uintptr_t *heapChunkBase = (uintptr_t *)region->getLowAddress(); /* Heap chunk base pointer */
uintptr_t *regionHighAddress = (uintptr_t *)region->getHighAddress();

while (heapChunkBase < regionHighAddress) {
void *poolHighAddr;
uintptr_t *heapChunkTop;
MM_MemoryPool *pool;

chunk = sectioningIterator.nextChunk();
Assert_MM_true(chunk != NULL); /* Should never return NULL */
totalChunkCount += 1;

/* Clear all data in the chunk (including sweep implementation specific information) */
chunk->clear();

if(((uintptr_t)regionHighAddress - (uintptr_t)heapChunkBase) < _extensions->parSweepChunkSize) {
/* corner case - we will wrap our address range */
heapChunkTop = regionHighAddress;
} else {
/* normal case - just increment by the chunk size */
heapChunkTop = (uintptr_t *)((uintptr_t)heapChunkBase + _extensions->parSweepChunkSize);
}

/* Find out if the range of memory we are considering spans 2 different pools. If it does,
* the current chunk can only be attributed to one, so we limit the upper range of the chunk
* to the first pool and will continue the assignment at the upper address range.
*/
pool = region->getSubSpace()->getMemoryPool(env, heapChunkBase, heapChunkTop, poolHighAddr);
if (NULL == poolHighAddr) {
heapChunkTop = (heapChunkTop > regionHighAddress ? regionHighAddress : heapChunkTop);
} else {
/* Yes ..so adjust chunk boundaries */
assume0(poolHighAddr > heapChunkBase && poolHighAddr < heapChunkTop);
heapChunkTop = (uintptr_t *) poolHighAddr;
}

/* All values for the chunk have been calculated - assign them */
chunk->chunkBase = (void *)heapChunkBase;
chunk->chunkTop = (void *)heapChunkTop;
chunk->memoryPool = pool;
Assert_MM_true(NULL != pool);
/* Some memory pools, like the one in LOA, may have larger min free size then in the rest of the heap being swept */
chunk->_minFreeSize = OMR_MAX(pool->getMinimumFreeEntrySize(), pool->getSweepPoolManager()->getMinimumFreeSize());

chunk->_coalesceCandidate = (heapChunkBase != region->getLowAddress());
chunk->_previous= previousChunk;
if(NULL != previousChunk) {
previousChunk->_next = chunk;
}

/* Move to the next chunk */
heapChunkBase = heapChunkTop;

/* and remember address of previous chunk */
previousChunk = chunk;

assume0((uintptr_t)heapChunkBase == MM_Math::roundToCeiling(_extensions->heapAlignment,(uintptr_t)heapChunkBase));
}
}
}

if(NULL != previousChunk) {
previousChunk->_next = NULL;
}

return totalChunkCount;
}

/**
* Allocate and initialize a new instance of the receiver.
* @return pointer to the new instance.
Expand Down
9 changes: 6 additions & 3 deletions gc/base/standard/SweepHeapSectioningSegmented.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2015 IBM Corp. and others
* Copyright (c) 1991, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand All @@ -24,6 +24,7 @@
#define SWEEPSCHEMESECTIONINGSEGMENTED_HPP_

#include "SweepHeapSectioning.hpp"
#include "HeapRegionDescriptor.hpp"

class MM_ParallelSweepChunkArray;
class MM_EnvironmentBase;
Expand All @@ -39,12 +40,14 @@ class MM_SweepHeapSectioningSegmented : public MM_SweepHeapSectioning
protected:
virtual uintptr_t estimateTotalChunkCount(MM_EnvironmentBase *env);
virtual uintptr_t calculateActualChunkNumbers() const;
virtual bool isReadyToSweep(MM_EnvironmentBase* env, MM_HeapRegionDescriptor* region)
{
return region->isCommitted();
}

public:
static MM_SweepHeapSectioningSegmented *newInstance(MM_EnvironmentBase *env);

virtual uintptr_t reassignChunks(MM_EnvironmentBase *env);

MM_SweepHeapSectioningSegmented(MM_EnvironmentBase *env)
: MM_SweepHeapSectioning(env)
{
Expand Down

0 comments on commit 6ffedb9

Please sign in to comment.