adding unit test for vx_malloc
This commit is contained in:
@@ -144,16 +144,20 @@ if [ $DEBUG -eq 1 ]
|
|||||||
then
|
then
|
||||||
if [ $SCOPE -eq 1 ]
|
if [ $SCOPE -eq 1 ]
|
||||||
then
|
then
|
||||||
|
echo "running: DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH"
|
||||||
DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
||||||
else
|
else
|
||||||
|
echo "running: DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH"
|
||||||
DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $HAS_ARGS -eq 1 ]
|
if [ $HAS_ARGS -eq 1 ]
|
||||||
then
|
then
|
||||||
|
echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER > run.log 2>&1"
|
||||||
OPTS=$ARGS make -C $APP_PATH run-$DRIVER > run.log 2>&1
|
OPTS=$ARGS make -C $APP_PATH run-$DRIVER > run.log 2>&1
|
||||||
status=$?
|
status=$?
|
||||||
else
|
else
|
||||||
|
echo "running: make -C $APP_PATH run-$DRIVER > run.log 2>&1"
|
||||||
make -C $APP_PATH run-$DRIVER > run.log 2>&1
|
make -C $APP_PATH run-$DRIVER > run.log 2>&1
|
||||||
status=$?
|
status=$?
|
||||||
fi
|
fi
|
||||||
@@ -163,18 +167,24 @@ then
|
|||||||
mv -f $APP_PATH/trace.vcd .
|
mv -f $APP_PATH/trace.vcd .
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
echo "driver initialization..."
|
||||||
if [ $SCOPE -eq 1 ]
|
if [ $SCOPE -eq 1 ]
|
||||||
then
|
then
|
||||||
|
echo "running: SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH"
|
||||||
SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
||||||
else
|
else
|
||||||
|
echo "running: CONFIGS="$CONFIGS" make -C $DRIVER_PATH"
|
||||||
CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
CONFIGS="$CONFIGS" make -C $DRIVER_PATH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "running application..."
|
||||||
if [ $HAS_ARGS -eq 1 ]
|
if [ $HAS_ARGS -eq 1 ]
|
||||||
then
|
then
|
||||||
|
echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER"
|
||||||
OPTS=$ARGS make -C $APP_PATH run-$DRIVER
|
OPTS=$ARGS make -C $APP_PATH run-$DRIVER
|
||||||
status=$?
|
status=$?
|
||||||
else
|
else
|
||||||
|
echo "running: make -C $APP_PATH run-$DRIVER"
|
||||||
make -C $APP_PATH run-$DRIVER
|
make -C $APP_PATH run-$DRIVER
|
||||||
status=$?
|
status=$?
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ set -e
|
|||||||
# ensure build
|
# ensure build
|
||||||
make -s
|
make -s
|
||||||
|
|
||||||
|
unittest()
|
||||||
|
{
|
||||||
|
make -C tests/unittest run
|
||||||
|
}
|
||||||
|
|
||||||
coverage()
|
coverage()
|
||||||
{
|
{
|
||||||
echo "begin coverage tests..."
|
echo "begin coverage tests..."
|
||||||
@@ -156,11 +161,13 @@ echo "stress1 tests done!"
|
|||||||
|
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
echo "usage: regression [-coverage] [-tex] [-cluster] [-debug] [-config] [-stress[#n]] [-all] [-h|--help]"
|
echo "usage: regression [-unittest] [-coverage] [-tex] [-cluster] [-debug] [-config] [-stress[#n]] [-all] [-h|--help]"
|
||||||
}
|
}
|
||||||
|
|
||||||
while [ "$1" != "" ]; do
|
while [ "$1" != "" ]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
|
-unittest ) unittest
|
||||||
|
;;
|
||||||
-coverage ) coverage
|
-coverage ) coverage
|
||||||
;;
|
;;
|
||||||
-tex ) tex
|
-tex ) tex
|
||||||
|
|||||||
@@ -4,19 +4,22 @@ import time
|
|||||||
import threading
|
import threading
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
PingInterval = 15
|
# This script executes a long-running command while outputing "still running ..." periodically
|
||||||
|
# to notify Travis build system that the program has not hanged
|
||||||
|
|
||||||
def PingCallback(stop):
|
PING_INTERVAL=15
|
||||||
|
|
||||||
|
def monitor(stop):
|
||||||
wait_time = 0
|
wait_time = 0
|
||||||
while True:
|
while True:
|
||||||
time.sleep(PingInterval)
|
time.sleep(PING_INTERVAL)
|
||||||
wait_time += PingInterval
|
wait_time += PING_INTERVAL
|
||||||
print(" + still running (" + str(wait_time) + "s) ...")
|
print(" + still running (" + str(wait_time) + "s) ...")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
if stop():
|
if stop():
|
||||||
break
|
break
|
||||||
|
|
||||||
def run_command(command):
|
def execute(command):
|
||||||
process = subprocess.Popen(command, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command, stdout=subprocess.PIPE)
|
||||||
while True:
|
while True:
|
||||||
output = process.stdout.readline()
|
output = process.stdout.readline()
|
||||||
@@ -24,18 +27,23 @@ def run_command(command):
|
|||||||
break
|
break
|
||||||
if output:
|
if output:
|
||||||
print output.strip()
|
print output.strip()
|
||||||
|
sys.stdout.flush()
|
||||||
return process.returncode
|
return process.returncode
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
|
|
||||||
stop_threads = False
|
# start monitoring thread
|
||||||
t = threading.Thread(target = PingCallback, args =(lambda : stop_threads, ))
|
stop_monitor = False
|
||||||
|
t = threading.Thread(target = monitor, args =(lambda : stop_monitor, ))
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
exitcode = run_command(argv)
|
# execute command
|
||||||
|
exitcode = execute(argv)
|
||||||
print(" + exitcode="+str(exitcode))
|
print(" + exitcode="+str(exitcode))
|
||||||
|
sys.stdout.flush()
|
||||||
stop_threads = True
|
|
||||||
|
# terminate monitoring thread
|
||||||
|
stop_monitor = True
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
sys.exit(exitcode)
|
sys.exit(exitcode)
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ public:
|
|||||||
|
|
||||||
~MemoryAllocator() {
|
~MemoryAllocator() {
|
||||||
// Free allocated pages
|
// Free allocated pages
|
||||||
page_t* pCurPage = pages_;
|
page_t* currPage = pages_;
|
||||||
while (pCurPage) {
|
while (currPage) {
|
||||||
auto nextPage = pCurPage->next;
|
auto nextPage = currPage->next;
|
||||||
this->DeletePage(pCurPage);
|
this->DeletePage(currPage);
|
||||||
pCurPage = nextPage;
|
currPage = nextPage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,143 +37,146 @@ public:
|
|||||||
size = AlignSize(size, blockAlign_);
|
size = AlignSize(size, blockAlign_);
|
||||||
|
|
||||||
// Walk thru all pages to find a free block
|
// Walk thru all pages to find a free block
|
||||||
block_t* pFreeBlock = nullptr;
|
block_t* freeBlock = nullptr;
|
||||||
auto pCurPage = pages_;
|
auto currPage = pages_;
|
||||||
while (pCurPage) {
|
while (currPage) {
|
||||||
auto pCurBlock = pCurPage->pFreeSList;
|
auto currBlock = currPage->freeSList;
|
||||||
if (pCurBlock) {
|
if (currBlock) {
|
||||||
// The free list is already sorted with biggest block on top,
|
// The free S-list is already sorted with the largest block first
|
||||||
// just check if the last block has enough space.
|
// Quick check if the head block has enough space.
|
||||||
if (pCurBlock->size >= size) {
|
if (currBlock->size >= size) {
|
||||||
// Find the smallest matching block
|
// Find the smallest matching block in the S-list
|
||||||
while (pCurBlock->nextFreeS
|
while (currBlock->nextFreeS
|
||||||
&& (pCurBlock->nextFreeS->size >= size)) {
|
&& (currBlock->nextFreeS->size >= size)) {
|
||||||
pCurBlock = pCurBlock->nextFreeS;
|
currBlock = currBlock->nextFreeS;
|
||||||
}
|
}
|
||||||
// Return the free block
|
// Return the free block
|
||||||
pFreeBlock = pCurBlock;
|
freeBlock = currBlock;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pCurPage = pCurPage->next;
|
currPage = currPage->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nullptr == pFreeBlock) {
|
if (nullptr == freeBlock) {
|
||||||
// Allocate a new page for this request
|
// Allocate a new page for this request
|
||||||
pCurPage = this->NewPage(size);
|
currPage = this->NewPage(size);
|
||||||
if (nullptr == pCurPage)
|
if (nullptr == currPage)
|
||||||
return -1;
|
return -1;
|
||||||
pFreeBlock = pCurPage->pFreeSList;
|
freeBlock = currPage->freeSList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the block from the free lists
|
// Remove the block from the free lists
|
||||||
assert(pFreeBlock->size >= size);
|
assert(freeBlock->size >= size);
|
||||||
pCurPage->RemoveFreeMBlock(pFreeBlock);
|
currPage->RemoveFreeMBlock(freeBlock);
|
||||||
pCurPage->RemoveFreeSBlock(pFreeBlock);
|
currPage->RemoveFreeSBlock(freeBlock);
|
||||||
|
|
||||||
// If the free block we have found is larger than what we are looking for,
|
// If the free block we have found is larger than what we are looking for,
|
||||||
// we may be able to split our free block in two.
|
// we may be able to split our free block in two.
|
||||||
uint64_t extraBytes = pFreeBlock->size - size;
|
uint64_t extraBytes = freeBlock->size - size;
|
||||||
if (extraBytes >= blockAlign_) {
|
if (extraBytes >= blockAlign_) {
|
||||||
// Reduce the free block size to the requested value
|
// Reduce the free block size to the requested value
|
||||||
pFreeBlock->size = size;
|
freeBlock->size = size;
|
||||||
|
|
||||||
// Allocate a new block to contain the extra buffer
|
// Allocate a new block to contain the extra buffer
|
||||||
auto nextAddr = pFreeBlock->addr + size;
|
auto nextAddr = freeBlock->addr + size;
|
||||||
auto pNewBlock = new block_t(nextAddr, extraBytes);
|
auto newBlock = new block_t(nextAddr, extraBytes);
|
||||||
|
|
||||||
// Add the new block to the free lists
|
// Add the new block to the free lists
|
||||||
pCurPage->InsertFreeMBlock(pNewBlock);
|
currPage->InsertFreeMBlock(newBlock);
|
||||||
pCurPage->InsertFreeSBlock(pNewBlock);
|
currPage->InsertFreeSBlock(newBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the free block into the used list
|
// Insert the free block into the used list
|
||||||
pCurPage->InsertUsedBlock(pFreeBlock);
|
currPage->InsertUsedBlock(freeBlock);
|
||||||
|
|
||||||
// Return the free block address
|
// Return the free block address
|
||||||
*addr = pFreeBlock->addr;
|
*addr = freeBlock->addr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int release(uint64_t addr) {
|
int release(uint64_t addr) {
|
||||||
// Walk all pages to find the pointer
|
// Walk all pages to find the pointer
|
||||||
block_t* pUsedBlock = nullptr;
|
block_t* usedBlock = nullptr;
|
||||||
auto pCurPage = pages_;
|
auto currPage = pages_;
|
||||||
while (pCurPage) {
|
while (currPage) {
|
||||||
if ((pCurPage->addr < addr)
|
if (addr >= currPage->addr
|
||||||
&& ((pCurPage->addr + pCurPage->size) > addr)) {
|
&& addr < (currPage->addr + currPage->size)) {
|
||||||
auto pCurBlock = pCurPage->pUsedList;
|
auto currBlock = currPage->usedList;
|
||||||
while (pCurBlock) {
|
while (currBlock) {
|
||||||
if (pCurBlock->addr == addr) {
|
if (currBlock->addr == addr) {
|
||||||
pUsedBlock = pCurBlock;
|
usedBlock = currBlock;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pCurBlock = pCurBlock->nextUsed;
|
currBlock = currBlock->nextUsed;
|
||||||
}
|
}
|
||||||
if (pUsedBlock)
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
pCurPage = pCurPage->next;
|
currPage = currPage->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found the corresponding block?
|
// found the corresponding block?
|
||||||
if (nullptr == pUsedBlock)
|
if (nullptr == usedBlock)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// Remove the block from the used list
|
// Remove the block from the used list
|
||||||
pCurPage->RemoveUsedBlock(pUsedBlock);
|
currPage->RemoveUsedBlock(usedBlock);
|
||||||
|
|
||||||
// Insert the block into the free M-list.
|
// Insert the block into the free M-list.
|
||||||
pCurPage->InsertFreeMBlock(pUsedBlock);
|
currPage->InsertFreeMBlock(usedBlock);
|
||||||
|
|
||||||
// Check if we can merge adjacent free blocks from the left.
|
// Check if we can merge adjacent free blocks from the left.
|
||||||
if (pUsedBlock->prevFreeM) {
|
if (usedBlock->prevFreeM) {
|
||||||
// Calculate the previous address
|
// Calculate the previous address
|
||||||
auto prevAddr = pUsedBlock->prevFreeM->addr + pUsedBlock->prevFreeM->size;
|
auto prevAddr = usedBlock->prevFreeM->addr + usedBlock->prevFreeM->size;
|
||||||
if (pUsedBlock->addr == prevAddr) {
|
if (usedBlock->addr == prevAddr) {
|
||||||
auto pMergedBlock = pUsedBlock->prevFreeM;
|
auto prevBlock = usedBlock->prevFreeM;
|
||||||
|
|
||||||
// Detach left block from the free S-list
|
|
||||||
pCurPage->RemoveFreeSBlock(pMergedBlock);
|
|
||||||
|
|
||||||
// Merge the blocks to the left
|
// Merge the blocks to the left
|
||||||
pMergedBlock->size += pUsedBlock->size;
|
prevBlock->size += usedBlock->size;
|
||||||
pMergedBlock->nextFreeM = pUsedBlock->nextFreeM;
|
prevBlock->nextFreeM = usedBlock->nextFreeM;
|
||||||
if (pMergedBlock->nextFreeM) {
|
if (prevBlock->nextFreeM) {
|
||||||
pMergedBlock->nextFreeM->prevFreeM = pMergedBlock;
|
prevBlock->nextFreeM->prevFreeM = prevBlock;
|
||||||
}
|
}
|
||||||
pUsedBlock = pMergedBlock;
|
|
||||||
|
// Detach previous block from the free S-list since size increased
|
||||||
|
currPage->RemoveFreeSBlock(prevBlock);
|
||||||
|
|
||||||
|
// reset usedBlock
|
||||||
|
delete usedBlock;
|
||||||
|
usedBlock = prevBlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we can merge adjacent free blocks from the right.
|
// Check if we can merge adjacent free blocks from the right.
|
||||||
if (pUsedBlock->nextFreeM) {
|
if (usedBlock->nextFreeM) {
|
||||||
// Calculate the next allocation start address
|
// Calculate the next allocation start address
|
||||||
auto nextMem = pUsedBlock->addr + pUsedBlock->size;
|
auto nextAddr = usedBlock->addr + usedBlock->size;
|
||||||
if (pUsedBlock->nextFreeM->addr == nextMem) {
|
if (usedBlock->nextFreeM->addr == nextAddr) {
|
||||||
auto nextBlock = pUsedBlock->nextFreeM;
|
auto nextBlock = usedBlock->nextFreeM;
|
||||||
|
|
||||||
// Detach right block from the free S-list
|
|
||||||
pCurPage->RemoveFreeSBlock(nextBlock);
|
|
||||||
|
|
||||||
// Merge the blocks to the right
|
// Merge the blocks to the right
|
||||||
pUsedBlock->size += nextBlock->size;
|
usedBlock->size += nextBlock->size;
|
||||||
pUsedBlock->nextFreeM = nextBlock->nextFreeM;
|
usedBlock->nextFreeM = nextBlock->nextFreeM;
|
||||||
if (pUsedBlock->nextFreeM) {
|
if (usedBlock->nextFreeM) {
|
||||||
pUsedBlock->nextFreeM->prevFreeM = pUsedBlock;
|
usedBlock->nextFreeM->prevFreeM = usedBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete next block
|
||||||
|
currPage->RemoveFreeSBlock(nextBlock);
|
||||||
|
delete nextBlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the block into the free S-list.
|
// Insert the block into the free S-list.
|
||||||
pCurPage->InsertFreeSBlock(pUsedBlock);
|
currPage->InsertFreeSBlock(usedBlock);
|
||||||
|
|
||||||
// Check if we can free empty pages
|
// Check if we can free empty pages
|
||||||
if (nullptr == pCurPage->pUsedList) {
|
if (nullptr == currPage->usedList) {
|
||||||
// Try to delete the page
|
// Try to delete the page
|
||||||
while (pCurPage && this->DeletePage(pCurPage)) {
|
while (currPage && this->DeletePage(currPage)) {
|
||||||
pCurPage = this->NextEmptyPage();
|
currPage = this->NextEmptyPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -212,110 +215,110 @@ private:
|
|||||||
page_t* next;
|
page_t* next;
|
||||||
|
|
||||||
// List of used blocks
|
// List of used blocks
|
||||||
block_t* pUsedList;
|
block_t* usedList;
|
||||||
|
|
||||||
// List with blocks sorted by descreasing sizes
|
// List with blocks sorted by descreasing sizes
|
||||||
// Used for block lookup during memory allocation.
|
// Used for block lookup during memory allocation.
|
||||||
block_t* pFreeSList;
|
block_t* freeSList;
|
||||||
|
|
||||||
// List with blocks sorted by increasing memory addresses
|
// List with blocks sorted by increasing memory addresses
|
||||||
// Used for block merging during memory release.
|
// Used for block merging during memory release.
|
||||||
block_t* pFreeMList;
|
block_t* freeMList;
|
||||||
|
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
|
||||||
page_t(uint64_t addr, uint64_t size) :
|
page_t(uint64_t addr, uint64_t size) :
|
||||||
next(nullptr),
|
next(nullptr),
|
||||||
pUsedList(nullptr),
|
usedList(nullptr),
|
||||||
addr(addr),
|
addr(addr),
|
||||||
size(size) {
|
size(size) {
|
||||||
pFreeSList = pFreeMList = new block_t(addr, size);
|
freeSList = freeMList = new block_t(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertUsedBlock(block_t* pBlock) {
|
void InsertUsedBlock(block_t* block) {
|
||||||
pBlock->nextUsed = pUsedList;
|
block->nextUsed = usedList;
|
||||||
if (pUsedList) {
|
if (usedList) {
|
||||||
pUsedList->prevUsed = pBlock;
|
usedList->prevUsed = block;
|
||||||
}
|
}
|
||||||
pUsedList = pBlock;
|
usedList = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveUsedBlock(block_t* pBlock) {
|
void RemoveUsedBlock(block_t* block) {
|
||||||
if (pBlock->prevUsed) {
|
if (block->prevUsed) {
|
||||||
pBlock->prevUsed->nextUsed = pBlock->nextUsed;
|
block->prevUsed->nextUsed = block->nextUsed;
|
||||||
} else {
|
} else {
|
||||||
pUsedList = pBlock->nextUsed;
|
usedList = block->nextUsed;
|
||||||
}
|
}
|
||||||
if (pBlock->nextUsed) {
|
if (block->nextUsed) {
|
||||||
pBlock->nextUsed->prevUsed = pBlock->prevUsed;
|
block->nextUsed->prevUsed = block->prevUsed;
|
||||||
}
|
}
|
||||||
pBlock->nextUsed = nullptr;
|
block->nextUsed = nullptr;
|
||||||
pBlock->prevUsed = nullptr;
|
block->prevUsed = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertFreeMBlock(block_t* pBlock) {
|
void InsertFreeMBlock(block_t* block) {
|
||||||
block_t* pCurBlock = pFreeMList;
|
block_t* currBlock = freeMList;
|
||||||
block_t* prevBlock = nullptr;
|
block_t* prevBlock = nullptr;
|
||||||
while (pCurBlock && (pCurBlock->addr < pBlock->addr)) {
|
while (currBlock && (currBlock->addr < block->addr)) {
|
||||||
prevBlock = pCurBlock;
|
prevBlock = currBlock;
|
||||||
pCurBlock = pCurBlock->nextFreeM;
|
currBlock = currBlock->nextFreeM;
|
||||||
}
|
}
|
||||||
pBlock->nextFreeM = pCurBlock;
|
block->nextFreeM = currBlock;
|
||||||
pBlock->prevFreeM = prevBlock;
|
block->prevFreeM = prevBlock;
|
||||||
if (prevBlock) {
|
if (prevBlock) {
|
||||||
prevBlock->nextFreeM = pBlock;
|
prevBlock->nextFreeM = block;
|
||||||
} else {
|
} else {
|
||||||
pFreeMList = pBlock;
|
freeMList = block;
|
||||||
}
|
}
|
||||||
if (pCurBlock) {
|
if (currBlock) {
|
||||||
pCurBlock->prevFreeM = pBlock;
|
currBlock->prevFreeM = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveFreeMBlock(block_t* pBlock) {
|
void RemoveFreeMBlock(block_t* block) {
|
||||||
if (pBlock->prevFreeM) {
|
if (block->prevFreeM) {
|
||||||
pBlock->prevFreeM->nextFreeM = pBlock->nextFreeM;
|
block->prevFreeM->nextFreeM = block->nextFreeM;
|
||||||
} else {
|
} else {
|
||||||
pFreeMList = pBlock->nextFreeM;
|
freeMList = block->nextFreeM;
|
||||||
}
|
}
|
||||||
if (pBlock->nextFreeM) {
|
if (block->nextFreeM) {
|
||||||
pBlock->nextFreeM->prevFreeM = pBlock->prevFreeM;
|
block->nextFreeM->prevFreeM = block->prevFreeM;
|
||||||
}
|
}
|
||||||
pBlock->nextFreeM = nullptr;
|
block->nextFreeM = nullptr;
|
||||||
pBlock->prevFreeM = nullptr;
|
block->prevFreeM = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertFreeSBlock(block_t* pBlock) {
|
void InsertFreeSBlock(block_t* block) {
|
||||||
block_t* pCurBlock = this->pFreeSList;
|
block_t* currBlock = this->freeSList;
|
||||||
block_t* prevBlock = nullptr;
|
block_t* prevBlock = nullptr;
|
||||||
while (pCurBlock && (pCurBlock->size > pBlock->size)) {
|
while (currBlock && (currBlock->size > block->size)) {
|
||||||
prevBlock = pCurBlock;
|
prevBlock = currBlock;
|
||||||
pCurBlock = pCurBlock->nextFreeS;
|
currBlock = currBlock->nextFreeS;
|
||||||
}
|
}
|
||||||
pBlock->nextFreeS = pCurBlock;
|
block->nextFreeS = currBlock;
|
||||||
pBlock->prevFreeS = prevBlock;
|
block->prevFreeS = prevBlock;
|
||||||
if (prevBlock) {
|
if (prevBlock) {
|
||||||
prevBlock->nextFreeS = pBlock;
|
prevBlock->nextFreeS = block;
|
||||||
} else {
|
} else {
|
||||||
this->pFreeSList = pBlock;
|
this->freeSList = block;
|
||||||
}
|
}
|
||||||
if (pCurBlock) {
|
if (currBlock) {
|
||||||
pCurBlock->prevFreeS = pBlock;
|
currBlock->prevFreeS = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveFreeSBlock(block_t* pBlock) {
|
void RemoveFreeSBlock(block_t* block) {
|
||||||
if (pBlock->prevFreeS) {
|
if (block->prevFreeS) {
|
||||||
pBlock->prevFreeS->nextFreeS = pBlock->nextFreeS;
|
block->prevFreeS->nextFreeS = block->nextFreeS;
|
||||||
} else {
|
} else {
|
||||||
pFreeSList = pBlock->nextFreeS;
|
freeSList = block->nextFreeS;
|
||||||
}
|
}
|
||||||
if (pBlock->nextFreeS) {
|
if (block->nextFreeS) {
|
||||||
pBlock->nextFreeS->prevFreeS = pBlock->prevFreeS;
|
block->nextFreeS->prevFreeS = block->prevFreeS;
|
||||||
}
|
}
|
||||||
pBlock->nextFreeS = nullptr;
|
block->nextFreeS = nullptr;
|
||||||
pBlock->prevFreeS = nullptr;
|
block->prevFreeS = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -332,54 +335,58 @@ private:
|
|||||||
if (nextAddress_ > maxAddress_)
|
if (nextAddress_ > maxAddress_)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Allocate the page
|
// Allocate object
|
||||||
auto pNewPage = new page_t(addr, size);
|
auto newPage = new page_t(addr, size);
|
||||||
|
|
||||||
// Insert the new page into the list
|
// Insert the new page into the list
|
||||||
pNewPage->next = pages_;
|
newPage->next = pages_;
|
||||||
pages_ = pNewPage;
|
pages_ = newPage;
|
||||||
|
|
||||||
return pNewPage;
|
return newPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeletePage(page_t* pPage) {
|
bool DeletePage(page_t* page) {
|
||||||
// The page should be empty
|
// The page should be empty
|
||||||
assert(nullptr == pPage->pUsedList);
|
assert(nullptr == page->usedList);
|
||||||
assert(pPage->pFreeMList && (nullptr == pPage->pFreeMList->nextFreeM));
|
assert(page->freeMList && (nullptr == page->freeMList->nextFreeM));
|
||||||
|
|
||||||
// Only delete top-level pages
|
// Only delete top-level pages
|
||||||
auto nextAddr = pPage->addr + pPage->size;
|
auto nextAddr = page->addr + page->size;
|
||||||
if (nextAddr != nextAddress_)
|
if (nextAddr != nextAddress_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Remove the page from the list
|
// Remove the page from the list
|
||||||
page_t* prevPage = nullptr;
|
page_t* prevPage = nullptr;
|
||||||
auto pCurPage = pages_;
|
auto currPage = pages_;
|
||||||
while (pCurPage) {
|
while (currPage) {
|
||||||
if (pCurPage == pPage) {
|
if (currPage == page) {
|
||||||
if (prevPage) {
|
if (prevPage) {
|
||||||
prevPage->next = pCurPage->next;
|
prevPage->next = currPage->next;
|
||||||
} else {
|
} else {
|
||||||
pages_ = pCurPage->next;
|
pages_ = currPage->next;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prevPage = pCurPage;
|
prevPage = currPage;
|
||||||
pCurPage = pCurPage->next;
|
currPage = currPage->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update next allocation address
|
// Update next allocation address
|
||||||
nextAddress_ = pPage->addr;
|
nextAddress_ = page->addr;
|
||||||
|
|
||||||
|
// free object
|
||||||
|
delete page->freeMList;
|
||||||
|
delete page;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
page_t* NextEmptyPage() {
|
page_t* NextEmptyPage() {
|
||||||
auto pCurPage = pages_;
|
auto currPage = pages_;
|
||||||
while (pCurPage) {
|
while (currPage) {
|
||||||
if (nullptr == pCurPage->pUsedList)
|
if (nullptr == currPage->usedList)
|
||||||
return pCurPage;
|
return currPage;
|
||||||
pCurPage = pCurPage->next;
|
currPage = currPage->next;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
all: runtime regression opencl riscv
|
all: runtime regression opencl riscv unittest
|
||||||
|
|
||||||
runtime:
|
runtime:
|
||||||
$(MAKE) -C runtime
|
$(MAKE) -C runtime
|
||||||
@@ -12,10 +12,14 @@ opencl:
|
|||||||
riscv:
|
riscv:
|
||||||
$(MAKE) -C riscv
|
$(MAKE) -C riscv
|
||||||
|
|
||||||
|
unittest:
|
||||||
|
$(MAKE) -C unittest
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) clean -C runtime
|
$(MAKE) clean -C runtime
|
||||||
$(MAKE) clean -C regression
|
$(MAKE) clean -C regression
|
||||||
$(MAKE) clean -C opencl
|
$(MAKE) clean -C opencl
|
||||||
$(MAKE) clean -C riscv
|
$(MAKE) clean -C riscv
|
||||||
|
$(MAKE) clean -C unittest
|
||||||
|
|
||||||
.PHONY: all runtime regression opencl riscv
|
.PHONY: all runtime regression opencl riscv unittest
|
||||||
8
tests/unittest/Makefile
Normal file
8
tests/unittest/Makefile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
all:
|
||||||
|
$(MAKE) -C vx_malloc
|
||||||
|
|
||||||
|
run:
|
||||||
|
$(MAKE) -C vx_malloc run
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C vx_malloc clean
|
||||||
34
tests/unittest/vx_malloc/Makefile
Normal file
34
tests/unittest/vx_malloc/Makefile
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
VORTEX_DRV_PATH ?= $(realpath ../../../driver)
|
||||||
|
|
||||||
|
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors
|
||||||
|
|
||||||
|
CXXFLAGS += -I$(VORTEX_DRV_PATH)/common
|
||||||
|
|
||||||
|
# Debugigng
|
||||||
|
ifdef DEBUG
|
||||||
|
CXXFLAGS += -g -O0
|
||||||
|
else
|
||||||
|
CXXFLAGS += -O2 -DNDEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
PROJECT = vx_malloc
|
||||||
|
|
||||||
|
SRCS = main.cpp
|
||||||
|
|
||||||
|
all: $(PROJECT)
|
||||||
|
|
||||||
|
$(PROJECT): $(SRCS)
|
||||||
|
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
run:
|
||||||
|
./$(PROJECT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROJECT) *.o .depend
|
||||||
|
|
||||||
|
clean-all: clean
|
||||||
|
rm -rf *.elf *.bin *.dump
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include .depend
|
||||||
|
endif
|
||||||
52
tests/unittest/vx_malloc/main.cpp
Normal file
52
tests/unittest/vx_malloc/main.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include <vx_malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define RT_CHECK(_expr) \
|
||||||
|
do { \
|
||||||
|
int _ret = _expr; \
|
||||||
|
if (0 == _ret) \
|
||||||
|
break; \
|
||||||
|
printf("Error: '%s' returned %d!\n", #_expr, (int)_ret); \
|
||||||
|
return -1; \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
static uint64_t minAddress = 0;
|
||||||
|
static uint64_t maxAddress = 0xffffffff;
|
||||||
|
static uint32_t pageAlign = 4096;
|
||||||
|
static uint32_t blockAlign = 64;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
auto allocator = new vortex::MemoryAllocator(
|
||||||
|
minAddress, maxAddress, pageAlign, blockAlign
|
||||||
|
);
|
||||||
|
|
||||||
|
uint64_t a0, a1, a2, a3;
|
||||||
|
|
||||||
|
RT_CHECK(allocator->allocate(128, &a0));
|
||||||
|
RT_CHECK(allocator->release(a0));
|
||||||
|
|
||||||
|
RT_CHECK(allocator->allocate(1, &a0));
|
||||||
|
RT_CHECK(allocator->allocate(1, &a1));
|
||||||
|
RT_CHECK(allocator->allocate(1, &a2));
|
||||||
|
RT_CHECK(allocator->release(a1));
|
||||||
|
RT_CHECK(allocator->allocate(1, &a3));
|
||||||
|
RT_CHECK(allocator->release(a0));
|
||||||
|
RT_CHECK(allocator->release(a2));
|
||||||
|
RT_CHECK(allocator->release(a3));
|
||||||
|
|
||||||
|
RT_CHECK(allocator->allocate(5878, &a0));
|
||||||
|
RT_CHECK(allocator->allocate(4095, &a1));
|
||||||
|
RT_CHECK(allocator->allocate(1, &a2));
|
||||||
|
RT_CHECK(allocator->allocate(1, &a3));
|
||||||
|
RT_CHECK(allocator->release(a0));
|
||||||
|
RT_CHECK(allocator->release(a1));
|
||||||
|
RT_CHECK(allocator->release(a2));
|
||||||
|
RT_CHECK(allocator->release(a3));
|
||||||
|
|
||||||
|
delete allocator;
|
||||||
|
|
||||||
|
printf("PASSED!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user