From 3b7475b01dc7825a656cbf1fd400508987cd5db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Tue, 6 Aug 2019 13:35:26 +0200 Subject: [PATCH] Add build option for changing the heap limit (#3005) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds a build option that allows adjusting the garbage collection heap usage limit, which can be used to fine-tune how often garbage collection should be triggered. JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu --- docs/01.CONFIGURATION.md | 15 +++++++++++++++ jerry-core/CMakeLists.txt | 7 +++++++ jerry-core/config.h | 12 ++++++++++++ jerry-core/jcontext/jcontext.h | 14 +++++++++++--- jerry-core/jmem/jmem-heap.c | 16 ++++++++-------- tools/build.py | 3 +++ 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/docs/01.CONFIGURATION.md b/docs/01.CONFIGURATION.md index b67634690..e6d886977 100644 --- a/docs/01.CONFIGURATION.md +++ b/docs/01.CONFIGURATION.md @@ -196,6 +196,21 @@ The default value is 512. | CMake: | `--DJERRY_GLOBAL_HEAP_SIZE=(int)` | | Python: | `--heap-size=(int)` | +### Garbage collection limit + +This option can be used to adjust the maximum allowed heap usage increase until triggering the next garbage collection, in bytes. +When the total allocated memory size reaches the current gc limit, garbage collection will be triggered to try and reduce clutter from unreachable objects. +If the total allocated memory can't be reduced below the current limit, then the limit will be increased by the amount specified via this option. +Similarly, when the total allocated memory goes well below the current gc limit, the limit is reduced by this amount. +The default value is 1/32 of the total heap size, but not greater than 8192 bytes. +A value of 0 will use the default value. + +| Options | | +|---------|----------------------------------------------| +| C: | `-DJERRY_GC_LIMIT=(int)` | +| CMake: | `-DJERRY_GC_LIMIT=(int)` | +| Python: | `--gc-limit=(int)` | + ### Stack limit This option can be used to cap the stack usage of the engine, and prevent stack overflows due to recursion. The provided value should be an integer, which represents the allowed stack usage in kilobytes. diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index 4c812b822..1cbc84283 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -39,6 +39,7 @@ set(JERRY_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system allocato set(JERRY_VALGRIND OFF CACHE BOOL "Enable Valgrind support?") set(JERRY_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution stopping?") set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes") +set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection") set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes") # Option overrides @@ -101,6 +102,7 @@ message(STATUS "JERRY_SYSTEM_ALLOCATOR " ${JERRY_SYSTEM_ALLOCATOR}) message(STATUS "JERRY_VALGRIND " ${JERRY_VALGRIND}) message(STATUS "JERRY_VM_EXEC_STOP " ${JERRY_VM_EXEC_STOP}) message(STATUS "JERRY_GLOBAL_HEAP_SIZE " ${JERRY_GLOBAL_HEAP_SIZE}) +message(STATUS "JERRY_GC_LIMIT " ${JERRY_GC_LIMIT}) message(STATUS "JERRY_STACK_LIMIT " ${JERRY_STACK_LIMIT}) # Include directories @@ -204,6 +206,11 @@ if(DEFINED JERRY_ATTR_GLOBAL_HEAP) set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ATTR_GLOBAL_HEAP=${JERRY_ATTR_GLOBAL_HEAP}) endif() +# Memory usage limit for triggering garbage collection +if(JERRY_GC_LIMIT) + set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GC_LIMIT=${JERRY_GC_LIMIT}) +endif() + # Helper macro to set 0/1 switch as Jerry Defines macro(jerry_add_define01 NAME) if(${NAME}) diff --git a/jerry-core/config.h b/jerry-core/config.h index 77bacb49a..68ef170bf 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -207,6 +207,15 @@ # define JERRY_GLOBAL_HEAP_SIZE (512) #endif /* !defined (JERRY_GLOBAL_HEAP_SIZE) */ +/** + * The allowed heap usage limit until next garbage collection, in bytes. + * + * If value is 0, the default is 1/32 of JERRY_HEAP_SIZE + */ +#ifndef JERRY_GC_LIMIT +# define JERRY_GC_LIMIT 0 +#endif /* !defined (JERRY_GC_LIMIT) */ + /** * Maximum stack usage size in kilobytes * @@ -613,6 +622,9 @@ #if !defined (JERRY_GLOBAL_HEAP_SIZE) || (JERRY_GLOBAL_HEAP_SIZE <= 0) # error "Invalid value for 'JERRY_GLOBAL_HEAP_SIZE' macro." #endif +#if !defined (JERRY_GC_LIMIT) || (JERRY_GC_LIMIT < 0) +# error "Invalid value for 'JERRY_GC_LIMIT' macro." +#endif #if !defined (JERRY_STACK_LIMIT) || (JERRY_STACK_LIMIT < 0) # error "Invalid value for 'JERRY_STACK_LIMIT' macro." #endif diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 93348c06b..dbbc03885 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -50,12 +50,20 @@ /** * Max heap usage limit */ -#define CONFIG_MEM_HEAP_MAX_LIMIT 8192 +#define CONFIG_MAX_GC_LIMIT 8192 /** - * Desired limit of heap usage + * Allowed heap usage limit until next garbage collection + * + * Whenever the total allocated memory size reaches the current heap limit, garbage collection will be triggered + * to try and reduce clutter from unreachable objects. If the allocated memory can't be reduced below the limit, + * then the current limit will be incremented by CONFIG_MEM_HEAP_LIMIT. */ -#define CONFIG_MEM_HEAP_DESIRED_LIMIT (JERRY_MIN (CONFIG_MEM_HEAP_SIZE / 32, CONFIG_MEM_HEAP_MAX_LIMIT)) +#if defined (JERRY_GC_LIMIT) && (JERRY_GC_LIMIT != 0) +#define CONFIG_GC_LIMIT JERRY_GC_LIMIT +#else +#define CONFIG_GC_LIMIT (JERRY_MIN (CONFIG_MEM_HEAP_SIZE / 32, CONFIG_MAX_GC_LIMIT)) +#endif /** * Amount of newly allocated objects since the last GC run, represented as a fraction of all allocated objects, diff --git a/jerry-core/jmem/jmem-heap.c b/jerry-core/jmem/jmem-heap.c index 7073ce2fd..badb079a2 100644 --- a/jerry-core/jmem/jmem-heap.c +++ b/jerry-core/jmem/jmem-heap.c @@ -79,7 +79,7 @@ jmem_heap_init (void) #endif /* !ENABLED (JERRY_CPOINTER_32_BIT) */ JERRY_ASSERT ((uintptr_t) JERRY_HEAP_CONTEXT (area) % JMEM_ALIGNMENT == 0); - JERRY_CONTEXT (jmem_heap_limit) = CONFIG_MEM_HEAP_DESIRED_LIMIT; + JERRY_CONTEXT (jmem_heap_limit) = CONFIG_GC_LIMIT; jmem_heap_free_t *const region_p = (jmem_heap_free_t *) JERRY_HEAP_CONTEXT (area); @@ -140,7 +140,7 @@ jmem_heap_alloc (const size_t size) /**< size of requested block */ if (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) { - JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT; + JERRY_CONTEXT (jmem_heap_limit) += CONFIG_GC_LIMIT; } if (data_space_p->size == JMEM_ALIGNMENT) @@ -223,7 +223,7 @@ jmem_heap_alloc (const size_t size) /**< size of requested block */ while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) { - JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT; + JERRY_CONTEXT (jmem_heap_limit) += CONFIG_GC_LIMIT; } break; @@ -252,7 +252,7 @@ jmem_heap_alloc (const size_t size) /**< size of requested block */ while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) { - JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT; + JERRY_CONTEXT (jmem_heap_limit) += CONFIG_GC_LIMIT; } return malloc (size); @@ -443,9 +443,9 @@ jmem_heap_free_block_internal (void *ptr, /**< pointer to beginning of data spac JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_allocated_size) > 0); JERRY_CONTEXT (jmem_heap_allocated_size) -= aligned_size; - while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_MEM_HEAP_DESIRED_LIMIT <= JERRY_CONTEXT (jmem_heap_limit)) + while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_GC_LIMIT <= JERRY_CONTEXT (jmem_heap_limit)) { - JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_MEM_HEAP_DESIRED_LIMIT; + JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_GC_LIMIT; } JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t)); @@ -453,9 +453,9 @@ jmem_heap_free_block_internal (void *ptr, /**< pointer to beginning of data spac #else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */ JERRY_CONTEXT (jmem_heap_allocated_size) -= size; - while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_MEM_HEAP_DESIRED_LIMIT <= JERRY_CONTEXT (jmem_heap_limit)) + while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_GC_LIMIT <= JERRY_CONTEXT (jmem_heap_limit)) { - JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_MEM_HEAP_DESIRED_LIMIT; + JERRY_CONTEXT (jmem_heap_limit) -= CONFIG_GC_LIMIT; } free (ptr); diff --git a/tools/build.py b/tools/build.py index 1b7abc7d8..d3efb5a40 100755 --- a/tools/build.py +++ b/tools/build.py @@ -120,6 +120,8 @@ def get_arguments(): help='enable logging (%(choices)s)') coregrp.add_argument('--mem-heap', metavar='SIZE', type=int, help='size of memory heap (in kilobytes)') + coregrp.add_argument('--gc-limit', metavar='SIZE', type=int, + help='memory usage limit to trigger garbage collection (in bytes)') coregrp.add_argument('--stack-limit', metavar='SIZE', type=int, help='maximum stack usage (in kilobytes)') coregrp.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], type=str.upper, @@ -195,6 +197,7 @@ def generate_build_options(arguments): build_options_append('JERRY_LINE_INFO', arguments.line_info) build_options_append('JERRY_LOGGING', arguments.logging) build_options_append('JERRY_GLOBAL_HEAP_SIZE', arguments.mem_heap) + build_options_append('JERRY_GC_LIMIT', arguments.gc_limit) build_options_append('JERRY_STACK_LIMIT', arguments.stack_limit) build_options_append('JERRY_MEM_STATS', arguments.mem_stats) build_options_append('JERRY_MEM_GC_BEFORE_EACH_ALLOC', arguments.mem_stress_test)