From ae436d1aed365f5a305c9f267ba7bd589f991784 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Thu, 23 Apr 2015 15:35:35 +0300 Subject: [PATCH 01/14] Supporting build with gcc/g++ version 4.7. Build was tested on arm-linux-gnueabi-gcc/g++ 4.7.3. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- CMakeLists.txt | 27 +++++++++++++++++++++------ jerry-core/jerry-extension.inc.h | 10 +++++----- jerry-core/mem/mem-pool.h | 4 ++-- jerry-core/parser/js/lexer.h | 2 +- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c68467932..c0f1f09488 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required (VERSION 2.8.12) project (Jerry CXX C ASM) -# Require g++ of version >= 4.8.0 +# Require g++ of version >= 4.7.0 if(NOT CMAKE_COMPILER_IS_GNUCXX) message(FATAL_ERROR "g++ compiler is required") else() @@ -23,8 +23,8 @@ project (Jerry CXX C ASM) OUTPUT_VARIABLE GNU_CXX_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - if(${GNU_CXX_VERSION} VERSION_LESS 4.8.0) - message(FATAL_ERROR "g++ compiler version 4.8.0 or higher required") + if(${GNU_CXX_VERSION} VERSION_LESS 4.7.0) + message(FATAL_ERROR "g++ compiler version 4.7.0 or higher required") endif() endif() @@ -177,7 +177,7 @@ project (Jerry CXX C ASM) set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -g -gdwarf-4") # Warnings - set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wall -Wextra -Wpedantic -Wlogical-op") + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wall -Wextra -pedantic -Wlogical-op") set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wformat-nonliteral -Winit-self -Wno-stack-protector") set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wconversion -Wsign-conversion -Wformat-security") set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wmissing-declarations -Wno-attributes") @@ -250,6 +250,19 @@ project (Jerry CXX C ASM) OUTPUT_STRIP_TRAILING_WHITESPACE) set_property(TARGET ${PREFIX_IMPORTED_LIB}libgcc PROPERTY IMPORTED_LOCATION ${IMPORTED_LIBGCC_LOCATION}) + # libgcc_eh + add_library(${PREFIX_IMPORTED_LIB}libgcc_eh STATIC IMPORTED) + execute_process(COMMAND ${CMAKE_C_COMPILER} ${FLAGS_COMMON_ARCH} -print-file-name=libgcc_eh.a + OUTPUT_VARIABLE IMPORTED_LIBGCC_EH_LOCATION + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(EXISTS "${IMPORTED_LIBGCC_EH_LOCATION}") + set_property(TARGET ${PREFIX_IMPORTED_LIB}libgcc_eh + PROPERTY IMPORTED_LOCATION ${IMPORTED_LIBGCC_EH_LOCATION}) + else() + # If libgcc_eh not found, reference libgcc instead + set_property(TARGET ${PREFIX_IMPORTED_LIB}libgcc_eh + PROPERTY IMPORTED_LOCATION ${IMPORTED_LIBGCC_LOCATION}) + endif() # Platform-specific configuration set(MODIFIERS_LISTS ${MODIFIERS_LISTS_${PLATFORM_EXT}}) @@ -307,7 +320,8 @@ project (Jerry CXX C ASM) target_compile_definitions(${TARGET_NAME} PRIVATE ${DEFINES_JERRY}) target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_CORE_INTERFACE}) target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDE_LIBC_INTERFACE}) - target_link_libraries(${TARGET_NAME} ${PLUGINS_TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libgcc) + target_link_libraries(${TARGET_NAME} ${PLUGINS_TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} + ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) add_cppcheck_target(${TARGET_NAME}) @@ -387,7 +401,8 @@ project (Jerry CXX C ASM) set_property(TARGET ${TARGET_NAME} PROPERTY LINK_FLAGS "${COMPILE_FLAGS_JERRY} ${CXX_FLAGS_JERRY} ${FLAGS_COMMON_UNITTESTS} ${LINKER_FLAGS_COMMON}") target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_CORE_INTERFACE}) - target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libc ${PREFIX_IMPORTED_LIB}libgcc) + target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libc + ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) add_cppcheck_target(${TARGET_NAME}) diff --git a/jerry-core/jerry-extension.inc.h b/jerry-core/jerry-extension.inc.h index b34265b808..2ea5b6cce9 100644 --- a/jerry-core/jerry-extension.inc.h +++ b/jerry-core/jerry-extension.inc.h @@ -39,10 +39,10 @@ enum static const jerry_extension_field_t jerry_extension_fields [JERRY_EXTENSION_FIELDS_NUMBER + 1] = { #define EXTENSION_FIELD(_field_name, _type, _value) \ - { # _field_name, JERRY_API_DATA_TYPE_ ## _type, _value }, + { # _field_name, JERRY_API_DATA_TYPE_ ## _type, { _value } }, # include EXTENSION_DESCRIPTION_HEADER #undef EXTENSION_FIELD -#define EMPTY_FIELD_ENTRY { NULL, JERRY_API_DATA_TYPE_UNDEFINED, NULL } +#define EMPTY_FIELD_ENTRY { NULL, JERRY_API_DATA_TYPE_UNDEFINED, { NULL } } EMPTY_FIELD_ENTRY #undef EMPTY_FIELD_ENTRY }; @@ -87,7 +87,7 @@ static const jerry_extension_field_t jerry_extension_fields [JERRY_EXTENSION_FIE /* Functions' arguments description */ #define EXTENSION_ARG(_arg_index, _type) [_arg_index] = { \ (JERRY_API_DATA_TYPE_ ## _type), \ - false /* just for initialization, should be overwritten upon call */ \ + { false } /* just for initialization, should be overwritten upon call */ \ } #define EXTENSION_FUNCTION(_function_name, _function_to_call, _ret_value_type, _args_number, ...) \ static jerry_api_value_t jerry_extension_function_ ## _function_name ## _args [_args_number] = { \ @@ -103,13 +103,13 @@ static jerry_extension_function_t jerry_extension_functions [JERRY_EXTENSION_FUN #define EXTENSION_FUNCTION(_function_name, _function_to_call, _ret_value_type, _args_number, ...) \ { \ # _function_name, jerry_extension_ ## _function_name ## _wrapper, \ - { JERRY_API_DATA_TYPE_ ## _ret_value_type, false }, \ + { JERRY_API_DATA_TYPE_ ## _ret_value_type, { false } }, \ jerry_extension_function_ ## _function_name ## _args, \ _args_number \ }, # include EXTENSION_DESCRIPTION_HEADER #undef EXTENSION_FUNCTION -#define EMPTY_FUNCTION_ENTRY { NULL, NULL, { JERRY_API_DATA_TYPE_VOID, false }, NULL, 0 } +#define EMPTY_FUNCTION_ENTRY { NULL, NULL, { JERRY_API_DATA_TYPE_VOID, { false } }, NULL, 0 } EMPTY_FUNCTION_ENTRY #undef EMPTY_FUNCTION_ENTRY }; diff --git a/jerry-core/mem/mem-pool.h b/jerry-core/mem/mem-pool.h index 64cdfbca02..c37bef11d8 100644 --- a/jerry-core/mem/mem-pool.h +++ b/jerry-core/mem/mem-pool.h @@ -59,10 +59,10 @@ typedef uint8_t mem_pool_chunk_index_t; typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) mem_pool_state_t { /** Offset of first free chunk from the beginning of the pool (mem_pool_chunk_index_t) */ - unsigned int first_free_chunk : MEM_POOL_MAX_CHUNKS_NUMBER_LOG; + mem_pool_chunk_index_t first_free_chunk : MEM_POOL_MAX_CHUNKS_NUMBER_LOG; /** Number of free chunks (mem_pool_chunk_index_t) */ - unsigned int free_chunks_number : MEM_POOL_MAX_CHUNKS_NUMBER_LOG; + mem_pool_chunk_index_t free_chunks_number : MEM_POOL_MAX_CHUNKS_NUMBER_LOG; /** Pointer to the next pool with same chunk size */ mem_cpointer_t next_pool_cp : MEM_COMPRESSED_POINTER_WIDTH; diff --git a/jerry-core/parser/js/lexer.h b/jerry-core/parser/js/lexer.h index 40b3e4009b..b9b0f5345f 100644 --- a/jerry-core/parser/js/lexer.h +++ b/jerry-core/parser/js/lexer.h @@ -19,7 +19,7 @@ #include "literal.h" #define INVALID_VALUE 255 -#define INVALID_LITERAL UINT32_MAX +#define INVALID_LITERAL ((uint32_t) -1) /* Keywords. */ typedef enum __attr_packed___ From 728ec47333ae81d8444cced0c9cae4ec05c1a673 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Thu, 23 Apr 2015 15:50:58 +0300 Subject: [PATCH 02/14] Splitting --mem-stats option to --mem-stats-at-exit and --mem-stats-per-opcode. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/jerry.cpp | 9 +++++---- jerry-core/jerry.h | 13 +++++++------ main-linux.cpp | 8 ++++++-- main-nuttx.cpp | 8 ++++++-- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 4220bf1c7c..8ece823a8c 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -904,7 +904,7 @@ jerry_init (jerry_flag_t flags) /**< combination of Jerry flags */ jerry_flags = flags; #ifndef MEM_STATS - if (flags & JERRY_FLAG_MEM_STATS) + if (flags & (JERRY_FLAG_MEM_STATS_AT_EXIT | JERRY_FLAG_MEM_STATS_PER_OPCODE)) { printf ("Ignoring memory statistics option because of '!MEM_STATS' build configuration.\n"); } @@ -921,7 +921,7 @@ jerry_init (jerry_flag_t flags) /**< combination of Jerry flags */ void jerry_cleanup (void) { - bool is_show_mem_stats = ((jerry_flags & JERRY_FLAG_MEM_STATS) != 0); + bool is_show_mem_stats = ((jerry_flags & JERRY_FLAG_MEM_STATS_AT_EXIT) != 0); ecma_finalize (); serializer_free (); @@ -966,8 +966,9 @@ jerry_parse (const char* source_p, /**< script source */ serializer_print_opcodes (); parser_free (); - bool is_show_mem_stats = ((jerry_flags & JERRY_FLAG_MEM_STATS) != 0); - init_int (opcodes, is_show_mem_stats); + bool is_show_mem_stats_per_opcode = ((jerry_flags & JERRY_FLAG_MEM_STATS_PER_OPCODE) != 0); + + init_int (opcodes, is_show_mem_stats_per_opcode); return true; } /* jerry_parse */ diff --git a/jerry-core/jerry.h b/jerry-core/jerry.h index b373d4f925..7df750a315 100644 --- a/jerry-core/jerry.h +++ b/jerry-core/jerry.h @@ -31,12 +31,13 @@ */ typedef uint32_t jerry_flag_t; -#define JERRY_FLAG_EMPTY (0) /**< empty flag set */ -#define JERRY_FLAG_SHOW_OPCODES (1 << 0) /**< dump opcodes to stdout after parse */ -#define JERRY_FLAG_MEM_STATS (1 << 1) /**< dump per-opcode memory statistics during execution - * (in the mode full GC is performed after each opcode handler) */ -#define JERRY_FLAG_PARSE_ONLY (1 << 2) /**< parse only, prevents script execution (only for testing) - * FIXME: Remove. */ +#define JERRY_FLAG_EMPTY (0) /**< empty flag set */ +#define JERRY_FLAG_SHOW_OPCODES (1 << 0) /**< dump opcodes to stdout after parse */ +#define JERRY_FLAG_MEM_STATS_AT_EXIT (1 << 1) /**< dump per-opcode memory statistics during execution + * (in the mode full GC is performed after each opcode handler) */ +#define JERRY_FLAG_MEM_STATS_PER_OPCODE (1 << 2) /**< dump peak memory statistics before exit */ +#define JERRY_FLAG_PARSE_ONLY (1 << 3) /**< parse only, prevents script execution (only for testing) + * FIXME: Remove. */ /** * Error codes diff --git a/main-linux.cpp b/main-linux.cpp index 8a49cec643..de0a2f4780 100644 --- a/main-linux.cpp +++ b/main-linux.cpp @@ -139,9 +139,13 @@ main (int argc, printf ("Branch name:\t%s\n", jerry_branch_name); printf ("\n"); } - else if (!strcmp ("--mem-stats", argv[i])) + else if (!strcmp ("--mem-stats-at-exit", argv[i])) { - flags |= JERRY_FLAG_MEM_STATS; + flags |= JERRY_FLAG_MEM_STATS_AT_EXIT; + } + else if (!strcmp ("--mem-stats-per-opcode", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS_PER_OPCODE; } else if (!strcmp ("--parse-only", argv[i])) { diff --git a/main-nuttx.cpp b/main-nuttx.cpp index 04fbaf9453..9e2dc342aa 100644 --- a/main-nuttx.cpp +++ b/main-nuttx.cpp @@ -146,9 +146,13 @@ int jerry_main (int argc, char *argv[]) printf ("Commit hash:\t%s\n", jerry_commit_hash); printf ("Branch name:\t%s\n", jerry_branch_name); } - else if (!strcmp ("--mem-stats", argv[i])) + else if (!strcmp ("--mem-stats-at-exit", argv[i])) { - flags |= JERRY_FLAG_MEM_STATS; + flags |= JERRY_FLAG_MEM_STATS_AT_EXIT; + } + else if (!strcmp ("--mem-stats-per-opcode", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS_PER_OPCODE; } else if (!strcmp ("--parse-only", argv[i])) { From 32e02681b03723a6f6d36392455706ffc066ae89 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 13:16:36 +0300 Subject: [PATCH 03/14] Making data and stack non-executable. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0f1f09488..502515f8af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,7 +162,7 @@ project (Jerry CXX C ASM) # Compiler / Linker flags set(COMPILE_FLAGS_JERRY "-fno-builtin") - set(LINKER_FLAGS_COMMON "") + set(LINKER_FLAGS_COMMON "-Wl,-z,noexecstack") # LTO if("${ENABLE_LTO}" STREQUAL "ON") From 41d585cf22de66a9b5816eba222f5f8dba7c999f Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 13:15:10 +0300 Subject: [PATCH 04/14] Removing measurements of metrics other than maximum RSS of non-executable areas from tools/rss_measure.sh. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- tools/rss-measure.sh | 78 +++----------------------------------------- 1 file changed, 5 insertions(+), 73 deletions(-) diff --git a/tools/rss-measure.sh b/tools/rss-measure.sh index b590acdba2..a9dd85f736 100755 --- a/tools/rss-measure.sh +++ b/tools/rss-measure.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2014 Samsung Electronics Co., Ltd. +# Copyright 2014-2015 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. @@ -16,27 +16,16 @@ JERRY=$1 TEST=$2 -RAW_OUTPUT=$3 -SLEEP=0.3 -REPEATS=5 - +SLEEP=0.1 Rss_OUT="" -Pss_OUT="" -Private_Dirty_OUT="" -Private_Clean_OUT="" -Shared_Dirty_OUT="" -Shared_Clean_OUT="" -Share_OUT="" -Size_OUT="" -Swap_OUT="" function collect_entry() { OUT_NAME="$1_OUT"; OUT=$OUT_NAME; - SUM=$(cat /proc/"$PID"/smaps 2>/dev/null | grep "$1" | awk '{sum += $2;} END { if (sum != 0) { print sum; }; }'); + SUM=$(grep -o -e "^[0-9a-f][0-9a-f]*.*" -e "^Rss.*" /proc/$PID/smaps 2>/dev/null | grep -A 1 -- "r[w-]-p " | grep "^Rss"|awk '{s += $2;} END {print s;}') if [ "$SUM" != "" ]; then @@ -49,7 +38,7 @@ function print_entry() OUT_NAME="$1_OUT"; OUT=$OUT_NAME; - eval "echo -e \"\$$OUT\"" | awk -v entry="$1" '{ if ($1 != "") { sum += $1; n += 1; if ($1 > max) { max = $1; } } } END { if (n == 0) { exit; }; printf "%19s:%8d Kb%19s:%8d Kb\n", entry, sum / n, entry, max; }'; + eval "echo -e \"\$$OUT\"" | awk -v entry="$1" '{ if ($1 != "") { n += 1; if ($1 > max) { max = $1; } } } END { if (n == 0) { exit; }; printf "%s:%8d Kb\n", entry, max; }'; } function run_test() @@ -60,68 +49,11 @@ function run_test() while kill -0 "$PID" > /dev/null 2>&1; do collect_entry Rss - collect_entry Pss - collect_entry Private_Dirty - collect_entry Private_Clean - collect_entry Shared_Dirty - collect_entry Shared_Clean - collect_entry Share - collect_entry Size - collect_entry Swap sleep $SLEEP - done } +run_test -ITERATIONS=`seq 1 $REPEATS` -START=$(date +%s.%N) - -for i in $ITERATIONS -do - run_test -done - -FINISH=$(date +%s.%N) - -echo - -if [ "$RAW_OUTPUT" != "" ]; -then - echo -e "$Rss_OUT"; - echo -e "$Pss_OUT"; - echo -e "$Private_Dirty_OUT"; - echo -e "$Private_Clean_OUT"; - echo -e "$Shared_Dirty_OUT"; - echo -e "$Shared_Clean_OUT"; - echo -e "$Share_OUT"; - echo -e "$Size_OUT"; - echo -e "$Swap_OUT"; -fi; - -if [ "$Size_OUT" == "" ] -then - echo "===================" - echo "Test failed." - echo "===================" - exit 1 -fi; - -TIME=$(echo "scale=3;($FINISH - $START) / 1.0" | bc ); -AVG_TIME=$(echo "scale=3;$TIME / $REPEATS" | bc ); - -echo "===================" -printf "%24sAVERAGE%28sMAX\n" "" ""; print_entry Rss -print_entry Pss -print_entry Private_Dirty -print_entry Private_Clean -print_entry Shared_Dirty -print_entry Shared_Clean -print_entry Share -print_entry Size -print_entry Swap -echo -e "---" -echo -e "Exec time / average:\t$TIME / $AVG_TIME secs" -echo "===================" From 677c5b4fba6a1161b71bbdaf95e3b3e4486e0c0e Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 13:23:21 +0300 Subject: [PATCH 05/14] Adding configuration option to execute GC after each opcode. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/config.h | 5 +++++ jerry-core/vm/vm.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/jerry-core/config.h b/jerry-core/config.h index 6d39bd58f4..89c4b3b626 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -170,4 +170,9 @@ */ #define CONFIG_EXTENSION_MAX_ARGUMENTS_IN_FUNCTION 16 +/** + * Run GC after execution of each opcode + */ +// #define CONFIG_VM_RUN_GC_AFTER_EACH_OPCODE + #endif /* !CONFIG_H */ diff --git a/jerry-core/vm/vm.cpp b/jerry-core/vm/vm.cpp index 846c0d0c3a..4cf9b073db 100644 --- a/jerry-core/vm/vm.cpp +++ b/jerry-core/vm/vm.cpp @@ -439,6 +439,10 @@ run_int_loop (int_data_t *int_data) completion = __opfuncs[curr->op_idx] (*curr, int_data); +#ifdef CONFIG_VM_RUN_GC_AFTER_EACH_OPCODE + ecma_gc_run (); +#endif /* CONFIG_VM_RUN_GC_AFTER_EACH_OPCODE */ + #ifdef MEM_STATS interp_mem_stats_opcode_exit (int_data, opcode_pos, From 98334e82e8b5e21f88eb5333fa5db50042ca92f1 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 13:32:27 +0300 Subject: [PATCH 06/14] Adding configuration option for disabling ECMA lookup cache. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/config.h | 5 +++++ jerry-core/ecma/base/ecma-lcache.cpp | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/jerry-core/config.h b/jerry-core/config.h index 89c4b3b626..c2d0bfac86 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -127,6 +127,11 @@ */ #define CONFIG_ECMA_STACK_FRAME_INLINED_VALUES_NUMBER (16) +/** + * Disable ECMA lookup cache + */ +// #define CONFIG_ECMA_LCACHE_DISABLE + /** * Link Global Environment to an empty declarative lexical environment * instead of lexical environment bound to Global Object. diff --git a/jerry-core/ecma/base/ecma-lcache.cpp b/jerry-core/ecma/base/ecma-lcache.cpp index 7ef34fbc80..7b63da691a 100644 --- a/jerry-core/ecma/base/ecma-lcache.cpp +++ b/jerry-core/ecma/base/ecma-lcache.cpp @@ -26,6 +26,7 @@ * @{ */ +#ifndef CONFIG_ECMA_LCACHE_DISABLE /** * Entry of LCache hash table */ @@ -65,6 +66,7 @@ JERRY_STATIC_ASSERT (sizeof (ecma_lcache_hash_entry_t) == sizeof (uint64_t)); * LCache's hash table */ static ecma_lcache_hash_entry_t ecma_lcache_hash_table[ ECMA_LCACHE_HASH_ROWS_COUNT ][ ECMA_LCACHE_HASH_ROW_LENGTH ]; +#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ /** * Initialize LCache @@ -72,9 +74,12 @@ static ecma_lcache_hash_entry_t ecma_lcache_hash_table[ ECMA_LCACHE_HASH_ROWS_CO void ecma_lcache_init (void) { +#ifndef CONFIG_ECMA_LCACHE_DISABLE memset (ecma_lcache_hash_table, 0, sizeof (ecma_lcache_hash_table)); +#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_init */ +#ifndef CONFIG_ECMA_LCACHE_DISABLE /** * Invalidate specified LCache entry */ @@ -98,6 +103,7 @@ ecma_lcache_invalidate_entry (ecma_lcache_hash_entry_t *entry_p) /**< entry to i false); } } /* ecma_lcache_invalidate_entry */ +#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ /** * Invalidate all entries in LCache @@ -105,6 +111,7 @@ ecma_lcache_invalidate_entry (ecma_lcache_hash_entry_t *entry_p) /**< entry to i void ecma_lcache_invalidate_all (void) { +#ifndef CONFIG_ECMA_LCACHE_DISABLE for (uint32_t row_index = 0; row_index < ECMA_LCACHE_HASH_ROWS_COUNT; row_index++) { for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++) @@ -115,8 +122,10 @@ ecma_lcache_invalidate_all (void) } } } +#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_invalidate_all */ +#ifndef CONFIG_ECMA_LCACHE_DISABLE /** * Invalidate entries of LCache's row that correspond to given (object, property) pair */ @@ -137,6 +146,7 @@ ecma_lcache_invalidate_row_for_object_property_pair (uint32_t row_index, /**< in } } } /* ecma_lcache_invalidate_row_for_object_property_pair */ +#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ /** * Insert an entry into LCache @@ -151,6 +161,7 @@ ecma_lcache_insert (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); +#ifndef CONFIG_ECMA_LCACHE_DISABLE prop_name_p = ecma_copy_or_ref_ecma_string (prop_name_p); ecma_string_hash_t hash_key = ecma_string_hash (prop_name_p); @@ -210,6 +221,9 @@ ecma_lcache_insert (ecma_object_t *object_p, /**< object */ ECMA_SET_NON_NULL_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].object_cp, object_p); ECMA_SET_NON_NULL_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_name_cp, prop_name_p); ECMA_SET_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_cp, prop_p); +#else /* CONFIG_ECMA_LCACHE_DISABLE */ + (void) prop_p; +#endif /* CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_insert */ /** @@ -228,6 +242,7 @@ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ * if return value is false, * then the output parameter is not set */ { +#ifndef CONFIG_ECMA_LCACHE_DISABLE ecma_string_hash_t hash_key = ecma_string_hash (prop_name_p); unsigned int object_cp; @@ -255,6 +270,11 @@ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ } } } +#else /* CONFIG_ECMA_LCACHE_DISABLE */ + (void) object_p; + (void) prop_name_p; + (void) prop_p_p; +#endif /* CONFIG_ECMA_LCACHE_DISABLE */ return false; } /* ecma_lcache_lookup */ @@ -276,6 +296,7 @@ ecma_lcache_invalidate (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_p != NULL || prop_name_arg_p != NULL); +#ifndef CONFIG_ECMA_LCACHE_DISABLE ecma_string_t *prop_name_p = NULL; if (prop_p != NULL) @@ -318,6 +339,7 @@ ecma_lcache_invalidate (ecma_object_t *object_p, /**< object */ * Given (object, property name) pair should be in the row corresponding to computed hash. */ ecma_lcache_invalidate_row_for_object_property_pair (hash_key, object_cp, prop_cp); +#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_invalidate */ /** From 601dc2ed80fbbbd326780f38ba64ca7ac5d8318d Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 13:49:32 +0300 Subject: [PATCH 07/14] Introducing minimal footprint build modifier (mfp). The modifier disables lookup cache and adds GC invocation after each opcode execution. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- CMakeLists.txt | 7 +++++++ Makefile | 2 +- jerry-core/CMakeLists.txt | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 502515f8af..c7161317de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,7 @@ project (Jerry CXX C ASM) COMPACT_PROFILE COMPACT_PROFILE_MINIMAL FULL_PROFILE + MINIMAL_FOOTPRINT MEMORY_STATISTICS) # Profiles @@ -131,6 +132,9 @@ project (Jerry CXX C ASM) # Minimal compact profile set(MODIFIER_SUFFIX_COMPACT_PROFILE_MINIMAL -cp_minimal) + # Minimal footprint + set(MODIFIER_SUFFIX_MINIMAL_FOOTPRINT -mfp) + # Memory statistics set(MODIFIER_SUFFIX_MEMORY_STATISTICS -mem_stats) @@ -140,7 +144,10 @@ project (Jerry CXX C ASM) "FULL_PROFILE" "COMPACT_PROFILE" "COMPACT_PROFILE_MINIMAL" + "FULL_PROFILE MINIMAL_FOOTPRINT" + "FULL_PROFILE MINIMAL_FOOTPRINT MEMORY_STATISTICS" "FULL_PROFILE MEMORY_STATISTICS" + "COMPACT_PROFILE_MINIMAL MINIMAL_FOOTPRINT" "COMPACT_PROFILE_MINIMAL MEMORY_STATISTICS") # MCU diff --git a/Makefile b/Makefile index 0cc3f45cf0..eec8d7fd86 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ export TARGET_RELEASE_MODES = release export TARGET_PC_SYSTEMS = linux export TARGET_NUTTX_SYSTEMS = nuttx -export TARGET_PC_MODS = cp cp_minimal mem_stats +export TARGET_PC_MODS = cp cp_minimal mem_stats mfp cp_minimal-mfp mfp-mem_stats export TARGET_NUTTX_MODS = $(TARGET_PC_MODS) export TARGET_MCU_MODS = cp cp_minimal diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index 27a0ab2b12..9caead6d25 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -66,6 +66,11 @@ project (JerryCore CXX C ASM) CONFIG_ECMA_COMPACT_PROFILE_DISABLE_JSON_BUILTIN CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN) + # Minimal footprint + set(DEFINES_MINIMAL_FOOTPRINT + CONFIG_ECMA_LCACHE_DISABLE + CONFIG_VM_RUN_GC_AFTER_EACH_OPCODE) + # Memory statistics set(DEFINES_MEMORY_STATISTICS MEM_STATS) From d91f102a2cef452631b3d28f010e35e268130404 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 15:56:31 +0300 Subject: [PATCH 08/14] Renaming --mem-stats-at-exit option to --mem-stats; adding --mem-stats-separate option for dumping memory statistics and resetting memory usage peak values after parse. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/jerry.cpp | 32 ++++++++++++++++++++++----- jerry-core/jerry.h | 15 +++++++------ jerry-core/mem/mem-allocator.cpp | 38 ++++++++++++++++++++++++++++++++ jerry-core/mem/mem-allocator.h | 5 +++++ main-linux.cpp | 8 +++++-- main-nuttx.cpp | 8 +++++-- 6 files changed, 89 insertions(+), 17 deletions(-) diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 8ece823a8c..ccfee573a2 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -27,6 +27,8 @@ #include "ecma-objects-general.h" #include "jerry.h" #include "jrt.h" +#include "mem-heap.h" +#include "mem-poolman.h" #include "parser.h" #include "serializer.h" #include "vm.h" @@ -901,14 +903,24 @@ jerry_api_eval (const char *source_p, /**< source code */ void jerry_init (jerry_flag_t flags) /**< combination of Jerry flags */ { - jerry_flags = flags; - -#ifndef MEM_STATS - if (flags & (JERRY_FLAG_MEM_STATS_AT_EXIT | JERRY_FLAG_MEM_STATS_PER_OPCODE)) + if (flags & (JERRY_FLAG_MEM_STATS)) { +#ifndef MEM_STATS + flags &= ~(JERRY_FLAG_MEM_STATS + | JERRY_FLAG_MEM_STATS_PER_OPCODE + | JERRY_FLAG_MEM_STATS_SEPARATE); + printf ("Ignoring memory statistics option because of '!MEM_STATS' build configuration.\n"); - } #endif /* !MEM_STATS */ + } + else if (flags & (JERRY_FLAG_MEM_STATS_PER_OPCODE | JERRY_FLAG_MEM_STATS_SEPARATE)) + { + flags &= ~(JERRY_FLAG_MEM_STATS_PER_OPCODE | JERRY_FLAG_MEM_STATS_SEPARATE); + + printf ("Ignoring detailed memory statistics options because memory statistics dump mode is not enabled.\n"); + } + + jerry_flags = flags; mem_init (); serializer_init (); @@ -921,7 +933,7 @@ jerry_init (jerry_flag_t flags) /**< combination of Jerry flags */ void jerry_cleanup (void) { - bool is_show_mem_stats = ((jerry_flags & JERRY_FLAG_MEM_STATS_AT_EXIT) != 0); + bool is_show_mem_stats = ((jerry_flags & JERRY_FLAG_MEM_STATS) != 0); ecma_finalize (); serializer_free (); @@ -966,6 +978,14 @@ jerry_parse (const char* source_p, /**< script source */ serializer_print_opcodes (); parser_free (); +#ifdef MEM_STATS + if (jerry_flags & JERRY_FLAG_MEM_STATS_SEPARATE) + { + mem_stats_print (); + mem_stats_reset_peak (); + } +#endif /* MEM_STATS */ + bool is_show_mem_stats_per_opcode = ((jerry_flags & JERRY_FLAG_MEM_STATS_PER_OPCODE) != 0); init_int (opcodes, is_show_mem_stats_per_opcode); diff --git a/jerry-core/jerry.h b/jerry-core/jerry.h index 7df750a315..45c60e5e52 100644 --- a/jerry-core/jerry.h +++ b/jerry-core/jerry.h @@ -31,13 +31,14 @@ */ typedef uint32_t jerry_flag_t; -#define JERRY_FLAG_EMPTY (0) /**< empty flag set */ -#define JERRY_FLAG_SHOW_OPCODES (1 << 0) /**< dump opcodes to stdout after parse */ -#define JERRY_FLAG_MEM_STATS_AT_EXIT (1 << 1) /**< dump per-opcode memory statistics during execution - * (in the mode full GC is performed after each opcode handler) */ -#define JERRY_FLAG_MEM_STATS_PER_OPCODE (1 << 2) /**< dump peak memory statistics before exit */ -#define JERRY_FLAG_PARSE_ONLY (1 << 3) /**< parse only, prevents script execution (only for testing) - * FIXME: Remove. */ +#define JERRY_FLAG_EMPTY (0u) /**< empty flag set */ +#define JERRY_FLAG_SHOW_OPCODES (1u << 0) /**< dump opcodes to stdout after parse */ +#define JERRY_FLAG_MEM_STATS (1u << 1) /**< dump memory statistics */ +#define JERRY_FLAG_MEM_STATS_PER_OPCODE (1u << 2) /**< dump per-opcode memory statistics during execution + * (in the mode full GC is performed after each opcode handler) */ +#define JERRY_FLAG_MEM_STATS_SEPARATE (1u << 3) /**< dump memory statistics and reset peak values after parse */ +#define JERRY_FLAG_PARSE_ONLY (1u << 4) /**< parse only, prevents script execution (only for testing) + * FIXME: Remove. */ /** * Error codes diff --git a/jerry-core/mem/mem-allocator.cpp b/jerry-core/mem/mem-allocator.cpp index b1f650dc19..0adb83a1b0 100644 --- a/jerry-core/mem/mem-allocator.cpp +++ b/jerry-core/mem/mem-allocator.cpp @@ -185,3 +185,41 @@ mem_is_heap_pointer (void *pointer) /**< pointer */ return (uint8_pointer >= mem_heap_area && uint8_pointer <= (mem_heap_area + MEM_HEAP_AREA_SIZE)); } /* mem_is_heap_pointer */ #endif /* !JERRY_NDEBUG */ + +#ifdef MEM_STATS +/** + * Reset peak values in memory usage statistics + */ +void +mem_stats_reset_peak (void) +{ + mem_heap_stats_reset_peak (); + mem_pools_stats_reset_peak (); +} /* mem_stats_reset_peak */ + +/** + * Print memory usage statistics + */ +void +mem_stats_print (void) +{ + mem_heap_print (false, false, true); + + mem_pools_stats_t stats; + mem_pools_get_stats (&stats); + + printf ("Pools stats:\n"); + printf (" Chunk size: %zu\n" + " Pools: %zu\n" + " Allocated chunks: %zu\n" + " Free chunks: %zu\n" + " Peak pools: %zu\n" + " Peak allocated chunks: %zu\n\n", + MEM_POOL_CHUNK_SIZE, + stats.pools_count, + stats.allocated_chunks, + stats.free_chunks, + stats.peak_pools_count, + stats.peak_allocated_chunks); +} /* mem_stats_print */ +#endif /* MEM_STATS */ diff --git a/jerry-core/mem/mem-allocator.h b/jerry-core/mem/mem-allocator.h index cb872ca0ae..a7e45d4a78 100644 --- a/jerry-core/mem/mem-allocator.h +++ b/jerry-core/mem/mem-allocator.h @@ -93,6 +93,11 @@ extern void mem_unregister_a_try_give_memory_back_callback (mem_try_give_memory_ extern bool mem_is_heap_pointer (void *pointer); #endif /* !JERRY_NDEBUG */ +#ifdef MEM_STATS +extern void mem_stats_reset_peak (void); +extern void mem_stats_print (void); +#endif /* MEM_STATS */ + #endif /* !JERRY_MEM_ALLOCATOR_H */ /** diff --git a/main-linux.cpp b/main-linux.cpp index de0a2f4780..26430470f5 100644 --- a/main-linux.cpp +++ b/main-linux.cpp @@ -139,14 +139,18 @@ main (int argc, printf ("Branch name:\t%s\n", jerry_branch_name); printf ("\n"); } - else if (!strcmp ("--mem-stats-at-exit", argv[i])) + else if (!strcmp ("--mem-stats", argv[i])) { - flags |= JERRY_FLAG_MEM_STATS_AT_EXIT; + flags |= JERRY_FLAG_MEM_STATS; } else if (!strcmp ("--mem-stats-per-opcode", argv[i])) { flags |= JERRY_FLAG_MEM_STATS_PER_OPCODE; } + else if (!strcmp ("--mem-stats-separate", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS_SEPARATE; + } else if (!strcmp ("--parse-only", argv[i])) { flags |= JERRY_FLAG_PARSE_ONLY; diff --git a/main-nuttx.cpp b/main-nuttx.cpp index 9e2dc342aa..bfc0661b1f 100644 --- a/main-nuttx.cpp +++ b/main-nuttx.cpp @@ -146,14 +146,18 @@ int jerry_main (int argc, char *argv[]) printf ("Commit hash:\t%s\n", jerry_commit_hash); printf ("Branch name:\t%s\n", jerry_branch_name); } - else if (!strcmp ("--mem-stats-at-exit", argv[i])) + else if (!strcmp ("--mem-stats", argv[i])) { - flags |= JERRY_FLAG_MEM_STATS_AT_EXIT; + flags |= JERRY_FLAG_MEM_STATS; } else if (!strcmp ("--mem-stats-per-opcode", argv[i])) { flags |= JERRY_FLAG_MEM_STATS_PER_OPCODE; } + else if (!strcmp ("--mem-stats-separate", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS_SEPARATE; + } else if (!strcmp ("--parse-only", argv[i])) { flags |= JERRY_FLAG_PARSE_ONLY; From 5a3cb1a9b25b05b6f0322df64a34c76bdd4c892b Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 16:35:30 +0300 Subject: [PATCH 09/14] Memory consumption measurement script. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- tools/mem_stats.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 tools/mem_stats.sh diff --git a/tools/mem_stats.sh b/tools/mem_stats.sh new file mode 100755 index 0000000000..a460413da2 --- /dev/null +++ b/tools/mem_stats.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# Copyright 2015 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. + +# Choosing table or semicolon-separated output mode +if [ "$1" == "-d" ] +then + TABLE="no" + PRINT_TEST_NAME_AWK_SCRIPT='{printf "%s;", $1}' + PRINT_TOTAL_AWK_SCRIPT='{printf "%d;%d;%d;%d\n", $1, $2, $4, $5 * 1024}' + + shift +else + PRINT_TEST_NAME_AWK_SCRIPT='{printf "%30s", $1}' + PRINT_TOTAL_AWK_SCRIPT='{printf "%25d%35d%35d%20d\n", $1, $2, $4, $5 * 1024}' + TABLE="yes" +fi + +# Engine +JERRY="$1" +shift + +# Benchmarks list +BENCHMARKS="" + +while [ $# -ne 0 ] +do + BENCHMARKS="$BENCHMARKS $1" + shift +done + +# Checking that the specified build supports memory statistics options +tmpfile=`mktemp` +$JERRY --mem-stats $tmpfile | grep -- "Ignoring memory statistics option because of '!MEM_STATS' build configuration." 2>&1 > /dev/null +code=$? +rm $tmpfile + +if [ $code -eq 0 ] +then + echo "Please, use engine built with mem_stats modifier." + + exit 1 +fi + +# Running +if [ "$TABLE" == "yes" ] +then + awk 'BEGIN {printf "%30s%25s%35s%35s%20s\n", "Test name", "Heap (byte-code)", "Heap (byte-code + parser)", "Heap (byte-code + execution)", "Maximum RSS"}' + echo +fi + +for bench in $BENCHMARKS +do + test=`basename -s '.js' $bench` + + echo "$test" | awk "$PRINT_TEST_NAME_AWK_SCRIPT" + ./tools/rss-measure.sh "$JERRY --mem-stats --mem-stats-separate" $bench | \ + grep -e "Peak allocated=" -e "Allocated =" -e "Rss" | grep -o "[0-9]*" | awk '{s=s" "$1;} END {print s;}' | \ + awk "$PRINT_TOTAL_AWK_SCRIPT" +done From d68abbd0c9f5005aa81f7fd0afa5bab7b92d5561 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 20:41:08 +0300 Subject: [PATCH 10/14] Removing mem_heap_try_to_resize_block interface. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/mem/mem-heap.cpp | 136 ------------------------------------ jerry-core/mem/mem-heap.h | 1 - tests/unit/test_heap.cpp | 22 ------ 3 files changed, 159 deletions(-) diff --git a/jerry-core/mem/mem-heap.cpp b/jerry-core/mem/mem-heap.cpp index edd32d87eb..5b72b8acef 100644 --- a/jerry-core/mem/mem-heap.cpp +++ b/jerry-core/mem/mem-heap.cpp @@ -652,142 +652,6 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to a } } /* mem_heap_alloc_block */ -/** - * Try to resize memory region. - * - * @return true - if resize is successful, - * false - if there is not enough memory in front of the block. - */ -bool -mem_heap_try_resize_block (void *ptr, /**< pointer to beginning of data space of the block to resize */ - size_t size_in_bytes) /**< new block size */ -{ - uint8_t *uint8_ptr = (uint8_t*) ptr; - - /* checking that uint8_ptr points to the heap */ - JERRY_ASSERT(uint8_ptr >= mem_heap.heap_start - && uint8_ptr <= mem_heap.heap_start + mem_heap.heap_size); - - mem_check_heap (); - - mem_block_header_t *block_p = (mem_block_header_t*) uint8_ptr - 1; - - VALGRIND_DEFINED_STRUCT(block_p); - - JERRY_ASSERT(block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK); - - /* For heap statistics unit we show what is going on as though - * the block is freed and then new block (the same or resized) - * is allocated */ - MEM_HEAP_STAT_FREE_BLOCK (block_p); - - size_t current_block_may_expand_up_to = mem_get_block_data_space_size (block_p); - - bool is_resized = false; - - if (current_block_may_expand_up_to >= size_in_bytes) - { - is_resized = true; - } - else - { - size_t need_additional_bytes = size_in_bytes - current_block_may_expand_up_to; - - mem_block_header_t *next_block_p = mem_get_next_block_by_direction (block_p, MEM_DIRECTION_NEXT); - - if (next_block_p != NULL) - { - VALGRIND_DEFINED_STRUCT (next_block_p); - - if (next_block_p->magic_num == MEM_MAGIC_NUM_OF_FREE_BLOCK) - { - size_t next_block_data_space_size = mem_get_block_data_space_size (next_block_p); - - if (next_block_data_space_size >= need_additional_bytes) - { - /* next block is free and contains enough space */ - - is_resized = true; - - size_t new_block_chunks_count = mem_get_block_chunks_count_from_data_size (size_in_bytes); - size_t current_block_chunks_count = mem_get_block_chunks_count (block_p); - size_t next_block_chunks_count = mem_get_block_chunks_count (next_block_p); - - JERRY_ASSERT (new_block_chunks_count <= current_block_chunks_count + next_block_chunks_count); - - size_t diff_in_chunks = (size_t) ((current_block_chunks_count + - next_block_chunks_count) - new_block_chunks_count); - - mem_block_header_t *block_after_next_p = mem_get_next_block_by_direction (next_block_p, - MEM_DIRECTION_NEXT); - mem_block_header_t *new_next_of_current_block_p; - mem_block_header_t *new_prev_of_block_after_next_p; - - if (diff_in_chunks > 0) - { - mem_block_header_t *new_free_block_p = (mem_block_header_t*) ((uint8_t*) block_p + - new_block_chunks_count * MEM_HEAP_CHUNK_SIZE); - - mem_init_block_header ((uint8_t*) new_free_block_p, - 0, - MEM_BLOCK_FREE, - block_p, - block_after_next_p); - - new_prev_of_block_after_next_p = new_free_block_p; - new_next_of_current_block_p = new_free_block_p; - } - else - { - new_prev_of_block_after_next_p = block_p; - new_next_of_current_block_p = block_after_next_p; - } - - mem_set_block_next (block_p, new_next_of_current_block_p); - if (block_after_next_p != NULL) - { - VALGRIND_DEFINED_STRUCT (block_after_next_p); - - mem_set_block_prev (block_after_next_p, new_prev_of_block_after_next_p); - - VALGRIND_NOACCESS_STRUCT (block_after_next_p); - } - else - { - mem_heap.last_block_p = new_prev_of_block_after_next_p; - } - } - } - else - { - JERRY_ASSERT (next_block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK); - } - - VALGRIND_NOACCESS_STRUCT (next_block_p); - } - } - - if (is_resized) - { - JERRY_ASSERT ((mem_heap_offset_t) size_in_bytes == size_in_bytes); - - if (size_in_bytes >= block_p->allocated_bytes) - { - VALGRIND_UNDEFINED_SPACE (uint8_ptr + block_p->allocated_bytes, size_in_bytes - block_p->allocated_bytes); - } - - mem_set_block_allocated_bytes (block_p, size_in_bytes); - } - - MEM_HEAP_STAT_ALLOC_BLOCK (block_p); - - VALGRIND_NOACCESS_STRUCT(block_p); - - mem_check_heap (); - - return is_resized; -} /* mem_heap_try_resize_block */ - /** * Free the memory block. */ diff --git a/jerry-core/mem/mem-heap.h b/jerry-core/mem/mem-heap.h index 203b147a33..b43e9afb8c 100644 --- a/jerry-core/mem/mem-heap.h +++ b/jerry-core/mem/mem-heap.h @@ -42,7 +42,6 @@ typedef enum extern void mem_heap_init (uint8_t *heap_start, size_t heap_size); extern void mem_heap_finalize (void); extern void* mem_heap_alloc_block (size_t size_in_bytes, mem_heap_alloc_term_t alloc_term); -extern bool mem_heap_try_resize_block (void *ptr, size_t size_in_bytes); extern void mem_heap_free_block (void *ptr); extern void* mem_heap_get_block_start (void *ptr); extern size_t __attr_pure___ mem_heap_recommend_allocation_size (size_t minimum_allocation_size); diff --git a/tests/unit/test_heap.cpp b/tests/unit/test_heap.cpp index e26d36eba8..b775e85870 100644 --- a/tests/unit/test_heap.cpp +++ b/tests/unit/test_heap.cpp @@ -118,28 +118,6 @@ main (int __attr_unused___ argc, // mem_heap_print (true); - for (uint32_t j = 0; j < test_sub_iters; j++) - { - if (ptrs[j] != NULL && (rand () % 2) == 0) - { - for (size_t k = 0; k < sizes[j]; k++) - { - JERRY_ASSERT(ptrs[j][k] == 0); - } - - size_t new_size = (size_t) rand () % (test_threshold_block_size); - - if (mem_heap_try_resize_block (ptrs[j], new_size)) - { - sizes[j] = new_size; - memset (ptrs[j], 0, sizes[j]); - } - - JERRY_ASSERT (sizes [j] == 0 - || mem_heap_get_block_start (ptrs[j] + (size_t) rand () % sizes [j]) == ptrs[j]); - } - } - for (uint32_t j = 0; j < test_sub_iters; j++) { if (ptrs[j] != NULL) From 6931ea80c37fff8c3f8105a5e4dfff42d070c93c Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Apr 2015 18:46:37 +0300 Subject: [PATCH 11/14] Introducing dynamically adjustable heap usage limit, so that GC tries to free heap space, when heap usage reached the limit. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/config.h | 5 +++++ jerry-core/mem/mem-heap.cpp | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/jerry-core/config.h b/jerry-core/config.h index c2d0bfac86..1e8b033b10 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -55,6 +55,11 @@ # define CONFIG_MEM_HEAP_AREA_SIZE (256 * 1024) #endif /* !CONFIG_MEM_HEAP_AREA_SIZE */ +/** + * Desired limit of heap usage + */ +#define CONFIG_MEM_HEAP_DESIRED_LIMIT (CONFIG_MEM_HEAP_AREA_SIZE / 32) + /** * Log2 of maximum possible offset in the heap * diff --git a/jerry-core/mem/mem-heap.cpp b/jerry-core/mem/mem-heap.cpp index 5b72b8acef..3f0446b66b 100644 --- a/jerry-core/mem/mem-heap.cpp +++ b/jerry-core/mem/mem-heap.cpp @@ -139,6 +139,9 @@ typedef struct size_t heap_size; /**< heap space size */ mem_block_header_t* first_block_p; /**< first block of the heap */ mem_block_header_t* last_block_p; /**< last block of the heap */ + size_t allocated_bytes; /**< total size of allocated heap space */ + size_t limit; /**< current limit of heap usage, that is upon being reached, + * causes call of "try give memory back" callbacks */ } mem_heap_state_t; /** @@ -382,6 +385,7 @@ mem_heap_init (uint8_t *heap_start, /**< first address of heap space */ mem_heap.heap_start = heap_start; mem_heap.heap_size = heap_size; + mem_heap.limit = CONFIG_MEM_HEAP_DESIRED_LIMIT; VALGRIND_NOACCESS_SPACE(heap_start, heap_size); @@ -510,6 +514,18 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size return NULL; } + mem_heap.allocated_bytes += size_in_bytes; + + JERRY_ASSERT (mem_heap.allocated_bytes <= mem_heap.heap_size); + + if (mem_heap.allocated_bytes >= mem_heap.limit) + { + mem_heap.limit = JERRY_MIN (mem_heap.heap_size, + JERRY_MAX (mem_heap.limit + CONFIG_MEM_HEAP_DESIRED_LIMIT, + mem_heap.allocated_bytes)); + JERRY_ASSERT (mem_heap.limit >= mem_heap.allocated_bytes); + } + /* appropriate block found, allocating space */ size_t new_block_size_in_chunks = mem_get_block_chunks_count_from_data_size (size_in_bytes); size_t found_block_size_in_chunks = mem_get_block_chunks_count (block_p); @@ -625,6 +641,11 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to a } else { + if (mem_heap.allocated_bytes >= mem_heap.limit) + { + mem_run_try_to_give_memory_back_callbacks (MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW); + } + void *data_space_p = mem_heap_alloc_block_internal (size_in_bytes, alloc_term); if (likely (data_space_p != NULL)) @@ -673,6 +694,23 @@ mem_heap_free_block (void *ptr) /**< pointer to beginning of data space of the b mem_block_header_t *prev_block_p = mem_get_next_block_by_direction (block_p, MEM_DIRECTION_PREV); mem_block_header_t *next_block_p = mem_get_next_block_by_direction (block_p, MEM_DIRECTION_NEXT); + JERRY_ASSERT (mem_heap.limit >= mem_heap.allocated_bytes); + + size_t bytes = block_p->allocated_bytes; + JERRY_ASSERT (mem_heap.allocated_bytes >= bytes); + mem_heap.allocated_bytes -= bytes; + + if (mem_heap.allocated_bytes * 3 <= mem_heap.limit) + { + mem_heap.limit /= 2; + } + else if (mem_heap.allocated_bytes + CONFIG_MEM_HEAP_DESIRED_LIMIT <= mem_heap.limit) + { + mem_heap.limit -= CONFIG_MEM_HEAP_DESIRED_LIMIT; + } + + JERRY_ASSERT (mem_heap.limit >= mem_heap.allocated_bytes); + MEM_HEAP_STAT_FREE_BLOCK (block_p); VALGRIND_NOACCESS_SPACE(uint8_ptr, block_p->allocated_bytes); @@ -927,6 +965,7 @@ mem_check_heap (void) bool is_last_block_was_met = false; size_t chunk_sizes_sum = 0; + size_t allocated_sum = 0; for (mem_block_header_t *block_p = mem_heap.first_block_p, *next_block_p; block_p != NULL; @@ -938,6 +977,11 @@ mem_check_heap (void) || block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK); chunk_sizes_sum += mem_get_block_chunks_count (block_p); + if (block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK) + { + allocated_sum += block_p->allocated_bytes; + } + next_block_p = mem_get_next_block_by_direction (block_p, MEM_DIRECTION_NEXT); if (block_p == mem_heap.last_block_p) @@ -955,6 +999,7 @@ mem_check_heap (void) } JERRY_ASSERT(chunk_sizes_sum * MEM_HEAP_CHUNK_SIZE == mem_heap.heap_size); + JERRY_ASSERT(allocated_sum == mem_heap.allocated_bytes); JERRY_ASSERT(is_last_block_was_met); bool is_first_block_was_met = false; From 7444422e787856738d2b293970ebede4bfa03b4d Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Mon, 27 Apr 2015 16:23:55 +0300 Subject: [PATCH 12/14] Fixing heap usage limit condition of starting GC. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/mem/mem-heap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jerry-core/mem/mem-heap.cpp b/jerry-core/mem/mem-heap.cpp index 3f0446b66b..6fb4c5e93e 100644 --- a/jerry-core/mem/mem-heap.cpp +++ b/jerry-core/mem/mem-heap.cpp @@ -641,7 +641,7 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to a } else { - if (mem_heap.allocated_bytes >= mem_heap.limit) + if (mem_heap.allocated_bytes + size_in_bytes >= mem_heap.limit) { mem_run_try_to_give_memory_back_callbacks (MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW); } From fb2d68cb63ce5c17beddc5dcb477316373c2d867 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Mon, 27 Apr 2015 19:48:43 +0300 Subject: [PATCH 13/14] Fixing RSS measurement in tools/mem_stats.sh: using mem_stats build for heap usage statistics and non-mem_stats build for RSS measurement. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- tools/mem_stats.sh | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/tools/mem_stats.sh b/tools/mem_stats.sh index a460413da2..eb64d393f4 100755 --- a/tools/mem_stats.sh +++ b/tools/mem_stats.sh @@ -28,9 +28,34 @@ else TABLE="yes" fi +function fail_msg +{ + echo "$1" + exit 1 +} + # Engine + +# Check if the specified build supports memory statistics options +function is_mem_stats_build +{ + [ -x "$1" ] || fail_msg "Engine '$1' is not executable" + + tmpfile=`mktemp` + "$1" --mem-stats $tmpfile | grep -- "Ignoring memory statistics option because of '!MEM_STATS' build configuration." 2>&1 > /dev/null + code=$? + rm $tmpfile + + return $code +} + JERRY="$1" shift +is_mem_stats_build "$JERRY" || fail_msg "First engine specified should be built without memory statistics support" + +JERRY_MEM_STATS="$1" +shift +is_mem_stats_build "$JERRY_MEM_STATS" && fail_msg "Second engine specified should be built with memory statistics support" # Benchmarks list BENCHMARKS="" @@ -41,19 +66,6 @@ do shift done -# Checking that the specified build supports memory statistics options -tmpfile=`mktemp` -$JERRY --mem-stats $tmpfile | grep -- "Ignoring memory statistics option because of '!MEM_STATS' build configuration." 2>&1 > /dev/null -code=$? -rm $tmpfile - -if [ $code -eq 0 ] -then - echo "Please, use engine built with mem_stats modifier." - - exit 1 -fi - # Running if [ "$TABLE" == "yes" ] then @@ -66,7 +78,7 @@ do test=`basename -s '.js' $bench` echo "$test" | awk "$PRINT_TEST_NAME_AWK_SCRIPT" - ./tools/rss-measure.sh "$JERRY --mem-stats --mem-stats-separate" $bench | \ - grep -e "Peak allocated=" -e "Allocated =" -e "Rss" | grep -o "[0-9]*" | awk '{s=s" "$1;} END {print s;}' | \ - awk "$PRINT_TOTAL_AWK_SCRIPT" + MEM_STATS=$("$JERRY_MEM_STATS" --mem-stats --mem-stats-separate $bench | grep -e "Peak allocated=" -e "Allocated =" | grep -o "[0-9]*") + RSS=$(./tools/rss-measure.sh "$JERRY" $bench | tail -n 1 | grep -e "Rss" | grep -o "[0-9]*") + echo $MEM_STATS $RSS | xargs | awk "$PRINT_TOTAL_AWK_SCRIPT" done From c543ef134485187dc34ac3edaa731ccc4c5b80b8 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Mon, 27 Apr 2015 17:56:48 +0300 Subject: [PATCH 14/14] Printing memory consumption notes in tools/log.sh (make log). JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- tools/git-scripts/log.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/git-scripts/log.sh b/tools/git-scripts/log.sh index d7c59555bd..6987cab724 100755 --- a/tools/git-scripts/log.sh +++ b/tools/git-scripts/log.sh @@ -17,6 +17,7 @@ git log --graph --branches --decorate \ --show-notes=perf --show-notes=mem --show-notes=test_build_env \ --show-notes=arm-linux-perf \ + --show-notes=arm-linux-memory-consumption \ --show-notes=arm-linux-binary-size \ --show-notes=stm32f4-binary-size