Commit b3330486 authored by Kunshan Wang's avatar Kunshan Wang

Fixed LOS allocation and block header size.

parent 33e433e5
......@@ -34,6 +34,7 @@ object HeaderUtils extends StrictLogging {
}
def setVarLength(objRef: Word, len: Word)(implicit memorySupport: MemorySupport) {
logger.debug("Storing varLength 0x%x at addr 0x%x".format(len, objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH))
memorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH, len)
}
......
......@@ -5,6 +5,7 @@ import TypeSizes._
import uvm.refimpl.mem.simpleimmix._
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import uvm.refimpl.mem.los.LargeObjectSpace
object MemoryManager {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
......@@ -16,8 +17,10 @@ class MemoryManager(val gcConf: GCConf)(implicit microVM: MicroVM) {
logger.info("sosSize=%d, losSize=%d, globalSize=%d, stackSize=%d".format(
gcConf.sosSize, gcConf.losSize, gcConf.globalSize, gcConf.stackSize))
require(gcConf.sosSize % 4096L == 0, "Small object space size must be 4096 bytes aligned. actual size: %d".format(gcConf.sosSize))
require(gcConf.losSize % 4096L == 0, "Large object space size must be 4096 bytes aligned. actual size: %d".format(gcConf.losSize))
require(gcConf.sosSize % SimpleImmixSpace.BLOCK_SIZE == 0, "Small object space size must be a multiple of %d bytes. actual size: %d".format(
SimpleImmixSpace.BLOCK_SIZE, gcConf.sosSize))
require(gcConf.losSize % LargeObjectSpace.BLOCK_SIZE == 0, "Large object space size must a multiple of %d bytes. actual size: %d".format(
LargeObjectSpace.BLOCK_SIZE, gcConf.losSize))
require(gcConf.globalSize % 4096L == 0, "Global space size must be 4096 bytes aligned. actual size: %d".format(gcConf.globalSize))
val totalMemorySize = gcConf.sosSize + gcConf.losSize + gcConf.globalSize
......
......@@ -20,7 +20,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = alignOf(ty)
val objAddr = alloc(size, align, GC_HEADER_SIZE_SCALAR)
HeaderUtils.postAllocScalar(objAddr, tag)
logger.debug("newScalar: objAddr=%d 0x%x, ty=%s".format(objAddr, objAddr, ty))
logger.trace("newScalar: objAddr=%d 0x%x, ty=%s".format(objAddr, objAddr, ty))
objAddr
}
......@@ -30,7 +30,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = hybridAlignOf(ty, len)
val objAddr = alloc(size, align, GC_HEADER_SIZE_HYBRID)
HeaderUtils.postAllocHybrid(objAddr, tag, len)
logger.debug("newHybrid: objAddr=%d 0x%x, len=%d 0x%x, ty=%s".format(objAddr, objAddr, len, len, ty))
logger.trace("newHybrid: objAddr=%d 0x%x, len=%d 0x%x, ty=%s".format(objAddr, objAddr, len, len, ty))
objAddr
}
......@@ -40,7 +40,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = alignOf(ty)
val objAddr = sm.alloc(size, align, GC_HEADER_SIZE_SCALAR)
HeaderUtils.postAllocScalar(objAddr, tag)
logger.debug("allocaScalar: objAddr=%d 0x%x, ty=%s".format(objAddr, objAddr, ty))
logger.trace("allocaScalar: objAddr=%d 0x%x, ty=%s".format(objAddr, objAddr, ty))
objAddr
}
......@@ -50,7 +50,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = hybridAlignOf(ty, len)
val objAddr = sm.alloc(size, align, GC_HEADER_SIZE_HYBRID)
HeaderUtils.postAllocHybrid(objAddr, tag, len)
logger.debug("allocaHybrid: objAddr=%d 0x%x, len=%d 0x%x, ty=%s".format(objAddr, objAddr, len, len, ty))
logger.trace("allocaHybrid: objAddr=%d 0x%x, len=%d 0x%x, ty=%s".format(objAddr, objAddr, len, len, ty))
objAddr
}
......
......@@ -13,12 +13,14 @@ object LargeObjectSpace {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
val BLOCK_SIZE = SimpleImmixSpace.BLOCK_SIZE / 4
private val OFFSET_PREV = 0 * TypeSizes.WORD_SIZE_BYTES
private val OFFSET_PREV = 0
private val OFFSET_NEXT = 1 * TypeSizes.WORD_SIZE_BYTES
private val OFFSET_NEXT = 8
private val OFFSET_MARK = 2 * TypeSizes.WORD_SIZE_BYTES
private val OFFSET_MARK = 16
private val BLOCK_HEADER_SIZE = 3 * TypeSizes.WORD_SIZE_BYTES
private val MARK_BIT = 0x1
}
......@@ -54,7 +56,7 @@ class LargeObjectSpace(val heap: SimpleImmixHeap, name: String, begin: Long, ext
private var head: Word = 0
def alloc(size: Word, align: Word, headerSize: Word): Word = {
val userStart = TypeSizes.alignUp(16 + headerSize, align)
val userStart = TypeSizes.alignUp(BLOCK_HEADER_SIZE + headerSize, align)
val totalSize = userStart + size
val nBlocks = (totalSize - 1) / BLOCK_SIZE + 1
if (nBlocks > 0xffffffffL) {
......
......@@ -8,6 +8,8 @@ import uvm.refimpl.itpr.OpHelper
import uvm.refimpl.itpr.InterpreterThread
import uvm.refimpl.itpr.InterpreterStack
import uvm.refimpl.UvmRefImplException
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
/**
* Handle references in the memory, value boxes or other Micro VM structures such as threads and stacks.
......@@ -37,6 +39,8 @@ trait RefFieldHandler {
}
object RefFieldUpdater {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
def updateBoxToHeap(box: HasObjRef, newObjRef: Word): Unit = box.setObjRef(newObjRef)
def updateBoxToStack(box: BoxStack, newStack: Option[InterpreterStack]) = box.stack = newStack
def updateMemToHeap(iRef: Word, isTR64: Boolean, newObjRef: Word)(implicit memorySupport: MemorySupport): Unit = {
......@@ -44,8 +48,17 @@ object RefFieldUpdater {
val oldRaw = memorySupport.loadLong(iRef)
val oldTag = OpHelper.tr64ToTag(oldRaw)
val newRaw = OpHelper.refToTr64(newObjRef, oldTag)
logger.debug {
val oldObjRef = OpHelper.tr64ToRef(oldRaw)
"Updating tagref field [0x%x] = 0x%x -> 0x%x; ref: 0x%x -> 0x%x".format(
iRef, oldRaw, newRaw, oldObjRef, newObjRef)
}
memorySupport.storeLong(iRef, newRaw)
} else {
logger.debug {
val oldObjRef = memorySupport.loadLong(iRef)
"Updating ref field [0x%x] = 0x%x -> 0x%x".format(iRef, oldObjRef, newObjRef)
}
memorySupport.storeLong(iRef, newObjRef)
}
}
......
......@@ -13,11 +13,44 @@ import com.typesafe.scalalogging.Logger
import scala.collection.mutable.ArrayBuffer
import uvm.refimpl.UvmRefImplException
import uvm.utils.HexDump
import scala.collection.mutable.HashSet
import com.typesafe.scalalogging.LazyLogging
object SimpleImmixCollector {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
private class MarkClearCheck extends LazyLogging {
val markedRefs = new HashSet[Word]()
val clearedRefs = new HashSet[Word]()
val diffRefs = new HashSet[Word]()
def beforeMarking(): Unit = {
markedRefs.clear
}
def marked(objRef: Word): Unit = {
markedRefs.add(objRef)
}
def beforeClearing(): Unit = {
clearedRefs.clear
}
def cleared(objRef: Word): Unit = {
clearedRefs.add(objRef)
}
def debugPrintStat(phase: String): Unit = {
diffRefs.clear()
for (r <- markedRefs if !clearedRefs.contains(r)) {
diffRefs.add(r)
}
logger.debug("After phase %s: nmarked:%d, ncleared:%d".format(phase, markedRefs.size, clearedRefs.size))
logger.debug("After phase %s: Refs marked but not cleared: \n".format(phase) + diffRefs.map(r => "0x%x\n".format(r)).mkString)
}
}
class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpace, val los: LargeObjectSpace)(
implicit microVM: MicroVM, memorySupport: MemorySupport)
extends Collector with Runnable {
......@@ -36,15 +69,22 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
// The number of times GC has run.
private var gcCount: Int = 0
private val MARK_CLEAR_DEBUG = false // Set to true if you want to check if any references are marked but not cleared
private val markClearCheck = if (MARK_CLEAR_DEBUG) Some(new MarkClearCheck()) else None
protected override def collect() {
gcCount += 1
logger.debug(s"GC starts. gcCount=${gcCount}")
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
logger.debug("Clearing stats...")
space.clearStats()
val weakRefs = new ArrayBuffer[Word]()
markClearCheck.map(_.beforeMarking())
logger.debug("Marking and getting statistics....")
val s1 = new AllScanner(new RefFieldHandler() {
......@@ -101,9 +141,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
}
}
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
markClearCheck.map(_.beforeClearing())
logger.debug("Stat finished. Unmarking....")
val s2 = new AllScanner(clearMarkHandler)
s2.scanAll()
markClearCheck.map(_.debugPrintStat("2"))
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
val resvSpace = space.getTotalReserveSpace
threshold = space.findThreshold(resvSpace)
......@@ -111,6 +159,10 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
defragMutator = new SimpleImmixDefragMutator(heap, space)
canDefrag = true
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
markClearCheck.map(_.beforeMarking())
logger.debug("Mark again, maybe move objects....")
val s3 = new AllScanner(markMover)
s3.scanAll()
......@@ -134,10 +186,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
notifyMovedObjectsToFutex()
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
markClearCheck.map(_.beforeClearing())
logger.debug("Blocks collected. Unmarking....")
val s4 = new AllScanner(clearMarkHandler)
s4.scanAll()
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
logger.debug("GC finished.")
heap.untriggerGC()
}
......@@ -150,13 +209,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
assert(addr != 0L, "addr should be non-zero before calling this function")
val oldHeader = HeaderUtils.getTag(addr)
logger.debug("GC header of 0x%x is 0x%x".format(addr, oldHeader))
val wasMarked = (oldHeader & MARK_MASK) != 0
val markBit = oldHeader & MARK_MASK
val moveBit = oldHeader & MOVE_MASK
val wasMarked = markBit != 0
val wasMoved = moveBit != 0
if (!wasMarked) {
val newHeader = oldHeader | MARK_MASK
HeaderUtils.setTag(addr, newHeader)
logger.debug("Newly marked 0x%x".format(addr))
markClearCheck.map(_.marked(addr))
logger.debug("MarkStat: Newly marked 0x%x".format(addr))
if (space.isInSpace(addr)) {
//space.markBlockByObjRef(addr)
//space.markBlockByObjRef(addr) // Unnecessary. Block mark is only cleared when collecting. Should do in phase3
val tag = HeaderUtils.getTag(addr)
val ty = HeaderUtils.getType(microVM, tag)
val used = ty match {
......@@ -171,7 +234,7 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
val blockNum = space.objRefToBlockIndex(addr)
space.incStat(blockNum, used)
} else if (los.isInSpace(addr)) {
//los.markBlockByObjRef(addr)
//los.markBlockByObjRef(addr) // Unnecessary. Block mark is only cleared when collecting. Should do in phase3
} else {
throw new UvmRefImplException("Object ref %d not in any space".format(addr))
}
......@@ -290,7 +353,8 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
val newHeader = oldHeader | MARK_MASK
HeaderUtils.setTag(actualObj, newHeader)
logger.debug("Newly marked 0x%x".format(actualObj))
markClearCheck.map(_.marked(actualObj))
logger.debug("MarkMove: Newly marked 0x%x".format(actualObj))
if (space.isInSpace(actualObj)) {
space.markBlockByObjRef(actualObj)
......@@ -318,24 +382,30 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
val ty = HeaderUtils.getType(microVM, tag)
try {
val (newObjRef, oldSize): (Long, Long) = ty match {
val (newObjRef, oldSize, oldVarLen): (Long, Long, Option[Long]) = ty match {
case htype: TypeHybrid => {
val len = HeaderUtils.getVarLength(oldObjRef)
val nor = defragMutator.newHybrid(htype, len)
val os = TypeSizes.hybridSizeOf(htype, len)
(nor, os)
(nor, os, Some(len))
}
case _ => {
val nor = defragMutator.newScalar(ty)
val os = TypeSizes.sizeOf(ty)
(nor, os)
(nor, os, None)
}
}
val alignedOldSize = TypeSizes.alignUp(oldSize, TypeSizes.WORD_SIZE_BYTES)
logger.debug("Copying old object 0x%x to 0x%x, %d bytes (aligned up to %d bytes).".format(
oldObjRef, newObjRef, oldSize, alignedOldSize))
MemUtils.memcpy(oldObjRef, newObjRef, alignedOldSize)
oldVarLen foreach { varLen =>
logger.debug("Copying old variable part length %d 0x%x to objref 0x%x".format(varLen, varLen, newObjRef))
HeaderUtils.setVarLength(newObjRef, varLen)
}
val newTag = newObjRef | MOVE_MASK
HeaderUtils.setTag(oldObjRef, newTag)
newObjRef
......@@ -394,9 +464,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
val oldHeader = HeaderUtils.getTag(objRef)
logger.debug("GC header of 0x%x is 0x%x".format(objRef, oldHeader))
val markBit = oldHeader & MARK_MASK
if (markBit != 0) {
val newHeader = oldHeader & ~(MARK_MASK | MOVE_MASK)
val moveBit = oldHeader & MOVE_MASK
val wasMarked = markBit != 0
val wasMoved = moveBit != 0
if (wasMoved) {
throw new UvmRefImplException("Should not point to tombstone when clearing marks. objRef: 0x%x".format(objRef))
}
if (wasMarked) {
val newHeader = oldHeader & ~MARK_MASK
HeaderUtils.setTag(objRef, newHeader)
markClearCheck.map(_.cleared(objRef))
logger.debug("MarkClear: Newly marked 0x%x (unmarking)".format(objRef))
Some(objRef)
} else {
None
......
......@@ -32,6 +32,7 @@ class SimpleImmixDefragMutator(val heap: SimpleImmixHeap, val space: SimpleImmix
case Some(addr) =>
cursor = addr
limit = addr + SimpleImmixSpace.BLOCK_SIZE
logger.debug("Got block. cursor=0x%x limit=0x%x".format(cursor, limit))
case None =>
}
}
......@@ -43,7 +44,7 @@ class SimpleImmixDefragMutator(val heap: SimpleImmixHeap, val space: SimpleImmix
throw new NoMoreDefragBlockException("No more blocks for defrag.")
}
val actualAlign = if (align < TypeSizes.WORD_SIZE_BYTES) TypeSizes.WORD_SIZE_BYTES else align
tryTwice {
val result = tryTwice {
val gcStart = TypeSizes.alignUp(cursor, align)
val userStart = TypeSizes.alignUp(gcStart + headerSize, align)
val userEnd = userStart + size
......@@ -65,6 +66,8 @@ class SimpleImmixDefragMutator(val heap: SimpleImmixHeap, val space: SimpleImmix
Some(userStart)
}
}
logger.debug("alloc(%d, %d, %d) = %d 0x%x".format(size, align, headerSize, result, result))
result
}
def close() {
......
......@@ -36,12 +36,13 @@ class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace,
curBlockAddr = Some(newAddr)
cursor = newAddr
limit = newAddr + SimpleImmixSpace.BLOCK_SIZE
logger.debug("Got block. cursor=0x%x limit=0x%x".format(cursor, limit))
}
override def alloc(size: Word, align: Word, headerSize: Word): Word = {
logger.debug(s"alloc(${size}, ${align}, ${headerSize})")
val actualAlign = if (align < TypeSizes.WORD_SIZE_BYTES) TypeSizes.WORD_SIZE_BYTES else align
tryRepeatedly { // Actually try at most twice.
val result = tryRepeatedly { // Actually try at most twice.
//If the first time failed, the second time cannot continue until a block is obtained.
val gcStart = TypeSizes.alignUp(cursor, align)
val userStart = TypeSizes.alignUp(gcStart + headerSize, align)
......@@ -60,6 +61,8 @@ class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace,
Some(userStart)
}
}
logger.debug("alloc(%d, %d, %d) = %d 0x%x".format(size, align, headerSize, result, result))
result
}
def close() {
......
......@@ -35,6 +35,18 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
}
val nBlocks: Int = (extend / BLOCK_SIZE).toInt
logger.debug {
val sb = new StringBuilder("Blocks:\n")
for (i <- 0L until nBlocks) {
val blockBegin = begin + i*BLOCK_SIZE
val blockEnd = begin + (i+1L)*BLOCK_SIZE
sb ++= " block[%d]: from %d 0x%x to %d 0x%x\n".format(i, blockBegin, blockBegin, blockEnd, blockEnd)
}
sb.toString
}
/** The number of reserved blocks (for defrag). */
private val nReserved: Int = Math.max(nBlocks / 20, 1) // reserve at least one block
......
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