diff --git a/Makefile b/Makefile index 29a579bd5..6072ba1ed 100644 --- a/Makefile +++ b/Makefile @@ -17,15 +17,21 @@ CROSS_COMPILE ?= arm-none-eabi- OBJ_DIR = obj OUT_DIR = ./out +MAIN_MODULE_SRC = ./src/main.c +UNITTESTS_SRC_DIR = ./tests/unit + +# FIXME: +# Place jerry-libc.c, pretty-printer.c to some subdirectory (libruntime?) +# and add them to the SOURCES list through wildcard. SOURCES = \ $(sort \ - $(wildcard ./src/*.c) \ + $(wildcard ./src/jerry-libc.c ./src/pretty-printer.c) \ $(wildcard ./src/libperipherals/*.c) \ $(wildcard ./src/libjsparser/*.c) \ $(wildcard ./src/libecmaobjects/*.c) \ $(wildcard ./src/liballocator/*.c) \ $(wildcard ./src/libcoreint/*.c) ) - + HEADERS = \ $(sort \ $(wildcard ./src/*.h) \ @@ -43,9 +49,14 @@ INCLUDES = \ -I src/liballocator \ -I src/libcoreint +UNITTESTS = \ + $(sort \ + $(patsubst %.c,%,$(notdir \ + $(wildcard $(UNITTESTS_SRC_DIR)/*)))) + OBJS = \ $(sort \ - $(patsubst %.c,./$(OBJ_DIR)/%.o,$(notdir $(SOURCES)))) + $(patsubst %.c,./$(OBJ_DIR)/%.o,$(notdir $(MAIN_MODULE_SRC) $(SOURCES)))) CC = gcc#-4.9 LD = ld @@ -79,21 +90,29 @@ DEFINES = -DMEM_HEAP_CHUNK_SIZE=256 -DMEM_HEAP_AREA_SIZE=32768 TARGET_HOST = -D__HOST TARGET_MCU = -D__MCU -.PHONY: all debug release clean check install +.PHONY: all debug release clean tests check install all: clean debug release check debug: mkdir -p $(OUT_DIR)/debug.host/ $(CC) $(CFLAGS) $(DEBUG_OPTIONS) $(DEFINES) $(TARGET_HOST) \ - $(SOURCES) -o $(OUT_DIR)/debug.host/$(TARGET) + $(SOURCES) $(MAIN_MODULE_SRC) -o $(OUT_DIR)/debug.host/$(TARGET) release: mkdir -p $(OUT_DIR)/release.host/ $(CC) $(CFLAGS) $(RELEASE_OPTIONS) $(DEFINES) $(TARGET_HOST) \ - $(SOURCES) -o $(OUT_DIR)/release.host/$(TARGET) + $(SOURCES) $(MAIN_MODULE_SRC) -o $(OUT_DIR)/release.host/$(TARGET) $(STRIP) $(OUT_DIR)/release.host/$(TARGET) +tests: + mkdir -p $(OUT_DIR)/tests.host/ + for unit_test in $(UNITTESTS); \ + do \ + $(CC) -O3 $(CFLAGS) $(DEBUG_OPTIONS) $(DEFINES) $(TARGET_HOST) \ + $(SOURCES) $(UNITTESTS_SRC_DIR)/"$$unit_test".c -o $(OUT_DIR)/tests.host/"$$unit_test"; \ + done + clean: rm -f $(OBJ_DIR)/*.o *.bin *.o *~ *.log *.log rm -rf $(OUT_DIR) @@ -104,19 +123,30 @@ clean: rm -f $(TARGET).hex rm -f $(TARGET).lst -check: - mkdir -p $(OUT_DIR) - cd $(OUT_DIR) - cppcheck $(HEADERS) $(SOURCES) --enable=all --std=c99 +check: tests + @mkdir -p $(OUT_DIR) + @cd $(OUT_DIR) + + @echo "=== Running cppcheck ===" + @cppcheck $(HEADERS) $(SOURCES) --enable=all --std=c99 + @echo Done + @echo - if [ -f $(OUT_DIR)/release.host/$(TARGET) ]; then \ - ./tools/jerry_test.sh $(OUT_DIR)/release.host/$(TARGET);\ + @echo "=== Running unit tests ===" + ./tools/jerry_unittest.sh $(OUT_DIR)/tests.host $(UNITTESTS) + @echo Done + @echo + + @echo "=== Running js tests ===" + @ if [ -f $(OUT_DIR)/release.host/$(TARGET) ]; then \ + ./tools/jerry_test.sh $(OUT_DIR)/release.host/$(TARGET);\ fi - if [ -f $(OUT_DIR)/debug.host/$(TARGET) ]; then \ - ./tools/jerry_test.sh $(OUT_DIR)/debug.host/$(TARGET);\ + @if [ -f $(OUT_DIR)/debug.host/$(TARGET) ]; then \ + ./tools/jerry_test.sh $(OUT_DIR)/debug.host/$(TARGET); \ fi - + @echo Done + @echo install: st-flash write $(TARGET).bin 0x08000000 diff --git a/src/liballocator/mem-poolman.c b/src/liballocator/mem-poolman.c index c516d6179..6e2b4fe1e 100644 --- a/src/liballocator/mem-poolman.c +++ b/src/liballocator/mem-poolman.c @@ -52,21 +52,6 @@ mem_PoolState_t mem_PoolForPoolHeaders; */ uint8_t *mem_SpaceForPoolForPoolHeaders; -/** - * Get chunk size from chunk type. - * - * @return size (in bytes) of chunk of specified type - */ -static size_t -mem_GetChunkSize( mem_PoolChunkType_t chunkType) /**< chunk type */ -{ - uint32_t chunkTypeId = (uint32_t) chunkType; - - JERRY_ASSERT( chunkTypeId < MEM_POOL_CHUNK_TYPE__COUNT ); - - return ( 1u << ( chunkTypeId + 2 ) ); -} /* mem_GetChunkSize */ - /** * Initialize pool manager */ diff --git a/src/liballocator/mem-poolman.h b/src/liballocator/mem-poolman.h index 2e6acdc3f..0426712dd 100644 --- a/src/liballocator/mem-poolman.h +++ b/src/liballocator/mem-poolman.h @@ -49,6 +49,21 @@ typedef enum { ((size) == 32 ? MEM_POOL_CHUNK_TYPE_32 : \ jerry_UnreferencedExpression)))) +/** + * Get chunk size from chunk type. + * + * @return size (in bytes) of chunk of specified type + */ +static inline size_t +mem_GetChunkSize( mem_PoolChunkType_t chunkType) /**< chunk type */ +{ + uint32_t chunkTypeId = (uint32_t) chunkType; + + JERRY_ASSERT( chunkTypeId < MEM_POOL_CHUNK_TYPE__COUNT ); + + return ( 1u << ( chunkTypeId + 2 ) ); +} /* mem_GetChunkSize */ + extern void mem_PoolsInit(void); extern uint8_t* mem_PoolsAlloc(mem_PoolChunkType_t chunkType); diff --git a/tests/unit/test_heap.c b/tests/unit/test_heap.c new file mode 100644 index 000000000..862df96fb --- /dev/null +++ b/tests/unit/test_heap.c @@ -0,0 +1,86 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "globals.h" +#include "mem-allocator.h" + +extern void srand (unsigned int __seed); +extern int rand (void); +extern long int time (long int *__timer); +extern int printf (__const char *__restrict __format, ...); +extern void *memset (void *__s, int __c, size_t __n); + +// Heap size is 8K +const size_t test_heap_size = 8 * 1024; + +// Iterations count +const uint32_t test_iters = 1024 * 1024; + +// Subiterations count +const uint32_t test_sub_iters = 3; + +// Threshold size of block to allocate +const uint32_t test_threshold_block_size = 2048; + +int +main( int __unused argc, + char __unused **argv) +{ + uint8_t test_native_heap[test_heap_size]; + + mem_HeapInit( test_native_heap, sizeof (test_native_heap)); + + srand((unsigned int) time(NULL)); + int k = rand(); + printf("seed=%d\n", k); + srand((unsigned int) k); + + mem_HeapPrint( false); + + for ( int i = 0; i < test_iters; i++ ) + { + const int subiters = test_sub_iters; + uint8_t * ptrs[subiters]; + size_t sizes[subiters]; + + for ( int j = 0; j < subiters; j++ ) + { + size_t size = (unsigned int) rand() % ( test_threshold_block_size ); + ptrs[j] = mem_HeapAllocBlock( size, ( rand() % 2 ) ? MEM_HEAP_ALLOC_SHORT_TERM : MEM_HEAP_ALLOC_SHORT_TERM); + sizes[j] = size; + if ( ptrs[j] != NULL ) + { + memset(ptrs[j], 0, sizes[j]); + } + // JERRY_ASSERT(ptrs[j] != NULL); + } + + // mem_HeapPrint( true); + + for ( int j = 0; j < subiters; j++ ) + { + if ( ptrs[j] != NULL ) + { + for( size_t k = 0; k < sizes[j]; k++ ) + { + JERRY_ASSERT( ptrs[j][k] == 0 ); + } + mem_HeapFreeBlock( ptrs[j]); + } + } + } + + return 0; +} /* main */ diff --git a/tests/unit/test_pool.c b/tests/unit/test_pool.c new file mode 100644 index 000000000..1a7f57d7e --- /dev/null +++ b/tests/unit/test_pool.c @@ -0,0 +1,91 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define JERRY_MEM_POOL_INTERNAL + +#include "globals.h" +#include "mem-allocator.h" +#include "mem-pool.h" + +extern void srand (unsigned int __seed); +extern int rand (void); +extern long int time (long int *__timer); +extern int printf (__const char *__restrict __format, ...); +extern void *memset (void *__s, int __c, size_t __n); + +// Pool area size is 8K +const size_t test_pool_area_size = 8 * 1024; + +// Iterations count +const uint32_t test_iters = 64; + +// Subiterations count +const uint32_t test_max_sub_iters = 1024; + +// Maximum size of chunk divided by MEM_ALIGNMENT +const uint32_t test_max_chunk_size_divided_by_alignment = 32; + +int +main( int __unused argc, + char __unused **argv) +{ + srand((unsigned int) time(NULL)); + int k = rand(); + printf("seed=%d\n", k); + srand((unsigned int) k); + + for ( int i = 0; i < test_iters; i++ ) + { + mem_PoolState_t pool; + uint8_t test_pool[test_pool_area_size] __attribute__((aligned(MEM_ALIGNMENT))); + + const size_t chunkSize = MEM_ALIGNMENT * ( ( rand() % test_max_chunk_size_divided_by_alignment ) + 1 ); + + mem_PoolInit( &pool, chunkSize, test_pool, sizeof (test_pool)); + + const size_t subiters = ( (size_t) rand() % test_max_sub_iters ) + 1; + uint8_t* ptrs[subiters]; + + for ( size_t j = 0; j < subiters; j++ ) + { + ptrs[j] = mem_PoolAllocChunk( &pool); + + // TODO: Enable check with condition that j <= minimum count of chunks that fit in the pool + // JERRY_ASSERT(ptrs[j] != NULL); + + if ( ptrs[j] != NULL ) + { + memset(ptrs[j], 0, chunkSize); + } + } + + // mem_HeapPrint( true); + + for ( size_t j = 0; j < subiters; j++ ) + { + if ( ptrs[j] != NULL ) + { + for ( size_t k = 0; k < chunkSize; k++ ) + { + JERRY_ASSERT( ((uint8_t*)ptrs[j])[k] == 0 ); + } + + mem_PoolFreeChunk( &pool, ptrs[j]); + } + } + } + + return 0; +} /* main */ diff --git a/tests/unit/test_poolman.c b/tests/unit/test_poolman.c new file mode 100644 index 000000000..a76b13e2f --- /dev/null +++ b/tests/unit/test_poolman.c @@ -0,0 +1,97 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Unit test for pool manager. + */ + +#define JERRY_MEM_POOL_INTERNAL + +#include "globals.h" +#include "jerry-libc.h" +#include "mem-allocator.h" +#include "mem-pool.h" +#include "mem-poolman.h" + +extern void srand (unsigned int __seed); +extern int rand (void); +extern long int time (long int *__timer); + +// Heap size is 8K +const size_t test_heap_size = 8 * 1024; + +// Iterations count +const uint32_t test_iters = 16384; + +// Subiterations count +const uint32_t test_max_sub_iters = 64; + +int +main( int __unused argc, + char __unused **argv) +{ + uint8_t heap[test_heap_size] __attribute__((aligned(MEM_ALIGNMENT))); + + mem_HeapInit( heap, sizeof (heap)); + mem_PoolsInit(); + + srand((unsigned int) time(NULL)); + unsigned int seed = (unsigned int)rand(); + libc_printf("seed=%u\n", seed); + srand(seed); + + for ( int i = 0; i < test_iters; i++ ) + { + const size_t subiters = ( (size_t) rand() % test_max_sub_iters ) + 1; + + uint8_t * ptrs[subiters]; + mem_PoolChunkType_t types[subiters]; + + for ( size_t j = 0; j < subiters; j++ ) + { + mem_PoolChunkType_t type = (mem_PoolChunkType_t) (rand() % MEM_POOL_CHUNK_TYPE__COUNT); + const uint32_t chunkSize = mem_GetChunkSize( type); + + types[j] = type; + ptrs[j] = mem_PoolsAlloc( type); + JERRY_ASSERT(ptrs[j] != NULL); + + if ( ptrs[j] != NULL ) + { + libc_memset(ptrs[j], 0, chunkSize); + } + } + + // mem_HeapPrint( false); + + for ( size_t j = 0; j < subiters; j++ ) + { + if ( ptrs[j] != NULL ) + { + mem_PoolChunkType_t type = types[j]; + const uint32_t chunkSize = mem_GetChunkSize( type); + + for ( size_t k = 0; k < chunkSize; k++ ) + { + JERRY_ASSERT( ((uint8_t*) ptrs[j])[k] == 0 ); + } + + mem_PoolsFree( type, ptrs[j]); + } + } + } + + return 0; +} /* main */ diff --git a/tools/jerry_unittest.sh b/tools/jerry_unittest.sh new file mode 100755 index 000000000..645aef2ce --- /dev/null +++ b/tools/jerry_unittest.sh @@ -0,0 +1,33 @@ +# Copyright 2014 Samsung Electronics Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/bin/bash + +DIR="$1" +UNITTESTS="${*:2}" + +for unit_test in $UNITTESTS; +do + echo -n "Running $unit_test... "; + + $DIR/$unit_test 2>&1 >> $DIR/unit_tests_run.log; + if [ $? -eq 0 ]; + then + echo OK; + else + echo FAILED; + exit 1; + fi; +done +