/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.genscavenge;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.log.Log;
This data is only updated during a GC.
ChunkBytes refer to bytes reserved (but maybe not occupied). ObjectBytes refer to bytes occupied
by objects.
/**
* This data is only updated during a GC.
*
* ChunkBytes refer to bytes reserved (but maybe not occupied). ObjectBytes refer to bytes occupied
* by objects.
*/
public final class GCAccounting {
/* State that is available to collection policies, etc. */
private long incrementalCollectionCount = 0;
private long incrementalCollectionTotalNanos = 0;
private long completeCollectionCount = 0;
private long completeCollectionTotalNanos = 0;
private UnsignedWord collectedTotalChunkBytes = WordFactory.zero();
private UnsignedWord allocatedChunkBytes = WordFactory.zero();
private UnsignedWord promotedTotalChunkBytes = WordFactory.zero();
private UnsignedWord copiedTotalChunkBytes = WordFactory.zero();
/* Before and after measures. */
private UnsignedWord youngChunkBytesBefore = WordFactory.zero();
private UnsignedWord youngChunkBytesAfter = WordFactory.zero();
private UnsignedWord oldChunkBytesBefore = WordFactory.zero();
private UnsignedWord oldChunkBytesAfter = WordFactory.zero();
private UnsignedWord lastCollectionPromotedChunkBytes = WordFactory.zero();
/*
* Bytes allocated in Objects, as opposed to bytes of chunks. These are only maintained if
* -R:+PrintGCSummary because they are expensive.
*/
private UnsignedWord collectedTotalObjectBytes = WordFactory.zero();
private UnsignedWord youngObjectBytesBefore = WordFactory.zero();
private UnsignedWord oldObjectBytesBefore = WordFactory.zero();
private UnsignedWord allocatedObjectBytes = WordFactory.zero();
@Platforms(Platform.HOSTED_ONLY.class)
GCAccounting() {
}
public long getIncrementalCollectionCount() {
return incrementalCollectionCount;
}
public long getIncrementalCollectionTotalNanos() {
return incrementalCollectionTotalNanos;
}
UnsignedWord getAllocatedChunkBytes() {
return allocatedChunkBytes;
}
public long getCompleteCollectionCount() {
return completeCollectionCount;
}
public long getCompleteCollectionTotalNanos() {
return completeCollectionTotalNanos;
}
UnsignedWord getCollectedTotalChunkBytes() {
return collectedTotalChunkBytes;
}
UnsignedWord getCollectedTotalObjectBytes() {
return collectedTotalObjectBytes;
}
UnsignedWord getAllocatedObjectBytes() {
return allocatedObjectBytes;
}
public UnsignedWord getOldGenerationAfterChunkBytes() {
return oldChunkBytesAfter;
}
UnsignedWord getYoungChunkBytesAfter() {
return youngChunkBytesAfter;
}
public static UnsignedWord getSurvivorSpaceAfterChunkBytes(int survivorIndex) {
return HeapImpl.getHeapImpl().getYoungGeneration().getSurvivorFromSpaceAt(survivorIndex).getChunkBytes();
}
UnsignedWord getLastCollectionPromotedChunkBytes() {
return lastCollectionPromotedChunkBytes;
}
void beforeCollection() {
Log trace = Log.noopLog().string("[GCImpl.Accounting.beforeCollection:").newline();
/* Gather some space statistics. */
HeapImpl heap = HeapImpl.getHeapImpl();
YoungGeneration youngGen = heap.getYoungGeneration();
youngChunkBytesBefore = youngGen.getChunkBytes();
/* This is called before the collection, so OldSpace is FromSpace. */
Space oldSpace = heap.getOldGeneration().getFromSpace();
oldChunkBytesBefore = oldSpace.getChunkBytes();
/* Objects are allocated in the young generation. */
allocatedChunkBytes = allocatedChunkBytes.add(youngChunkBytesBefore);
if (HeapOptions.PrintGCSummary.getValue()) {
youngObjectBytesBefore = youngGen.computeObjectBytes();
oldObjectBytesBefore = oldSpace.computeObjectBytes();
allocatedObjectBytes = allocatedObjectBytes.add(youngObjectBytesBefore);
}
trace.string(" youngChunkBytesBefore: ").unsigned(youngChunkBytesBefore)
.string(" oldChunkBytesBefore: ").unsigned(oldChunkBytesBefore);
trace.string("]").newline();
}
void afterCollection(boolean completeCollection, Timer collectionTimer) {
if (completeCollection) {
afterCompleteCollection(collectionTimer);
} else {
afterIncrementalCollection(collectionTimer);
}
}
private void afterIncrementalCollection(Timer collectionTimer) {
Log trace = Log.noopLog().string("[GCImpl.Accounting.afterIncrementalCollection:");
/*
* Aggregating collection information is needed because any given collection policy may not
* be called for all collections, but may want to make decisions based on the aggregate
* values.
*/
incrementalCollectionCount += 1;
afterCollectionCommon();
/* Incremental collections only promote. */
lastCollectionPromotedChunkBytes = oldChunkBytesAfter.subtract(oldChunkBytesBefore);
promotedTotalChunkBytes = promotedTotalChunkBytes.add(lastCollectionPromotedChunkBytes);
incrementalCollectionTotalNanos += collectionTimer.getMeasuredNanos();
trace.string(" incrementalCollectionCount: ").signed(incrementalCollectionCount)
.string(" oldChunkBytesAfter: ").unsigned(oldChunkBytesAfter)
.string(" oldChunkBytesBefore: ").unsigned(oldChunkBytesBefore)
.string(" promotedChunkBytes: ").unsigned(lastCollectionPromotedChunkBytes);
trace.string("]").newline();
}
private void afterCompleteCollection(Timer collectionTimer) {
Log trace = Log.noopLog().string("[GCImpl.Accounting.afterCompleteCollection:");
completeCollectionCount += 1;
afterCollectionCommon();
/* Complete collections only copy, and they copy everything. */
copiedTotalChunkBytes = copiedTotalChunkBytes.add(oldChunkBytesAfter);
completeCollectionTotalNanos += collectionTimer.getMeasuredNanos();
trace.string(" completeCollectionCount: ").signed(completeCollectionCount)
.string(" oldChunkBytesAfter: ").unsigned(oldChunkBytesAfter);
trace.string("]").newline();
}
void afterCollectionCommon() {
HeapImpl heap = HeapImpl.getHeapImpl();
// This is called after the collection, after the space flip, so OldSpace is FromSpace.
YoungGeneration youngGen = heap.getYoungGeneration();
youngChunkBytesAfter = youngGen.getChunkBytes();
Space oldSpace = heap.getOldGeneration().getFromSpace();
oldChunkBytesAfter = oldSpace.getChunkBytes();
UnsignedWord beforeChunkBytes = youngChunkBytesBefore.add(oldChunkBytesBefore);
UnsignedWord afterChunkBytes = oldChunkBytesAfter.add(youngChunkBytesAfter);
UnsignedWord collectedChunkBytes = beforeChunkBytes.subtract(afterChunkBytes);
collectedTotalChunkBytes = collectedTotalChunkBytes.add(collectedChunkBytes);
if (HeapOptions.PrintGCSummary.getValue()) {
UnsignedWord youngObjectBytesAfter = youngGen.computeObjectBytes();
UnsignedWord oldObjectBytesAfter = oldSpace.computeObjectBytes();
UnsignedWord beforeObjectBytes = youngObjectBytesBefore.add(oldObjectBytesBefore);
UnsignedWord collectedObjectBytes = beforeObjectBytes.subtract(oldObjectBytesAfter).subtract(youngObjectBytesAfter);
collectedTotalObjectBytes = collectedTotalObjectBytes.add(collectedObjectBytes);
}
}
}