mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Add simple stack measure for jerry-test (#3717)
This change introduces simple stack measuring by coloring the stack before doing the actual JS work. The dynamic linking should be avoided as it will use the stack during the symbol resolving. At this moment the `JERRY_STACK_MEASURE` compile time define will enable the measurement for the jerry-test binary. A usable build configuration: ``` ./tools/build.py --jerry-cmdline-test=on --compile-flag=-DJERRY_STACK_MEASURE=1 --compile-flag=-static ``` JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.usz@partner.samsung.com
This commit is contained in:
parent
cd1e067671
commit
eb77f96d20
@ -17,9 +17,11 @@ project (jerry-main C)
|
||||
|
||||
# Optional build settings
|
||||
set(ENABLE_LINK_MAP OFF CACHE BOOL "Enable generating a link map file?")
|
||||
set(JERRY_TEST_STACK_MEASURE OFF CACHE BOOL "Enable stack measurement for the jerry-test binary?")
|
||||
|
||||
# Status messages
|
||||
message(STATUS "ENABLE_LINK_MAP " ${ENABLE_LINK_MAP})
|
||||
message(STATUS "JERRY_TEST_STACK_MEASURE " ${JERRY_TEST_STACK_MEASURE})
|
||||
|
||||
# Generate map file
|
||||
if(ENABLE_LINK_MAP)
|
||||
@ -69,6 +71,7 @@ endif()
|
||||
if(JERRY_CMDLINE_TEST)
|
||||
jerry_create_executable("jerry-test" "main-unix-test.c" "benchmarking.c")
|
||||
target_link_libraries("jerry-test" jerry-port-default-minimal)
|
||||
target_compile_definitions("jerry-test" PRIVATE -DJERRY_TEST_STACK_MEASURE=1)
|
||||
endif()
|
||||
|
||||
if(JERRY_CMDLINE_SNAPSHOT)
|
||||
|
||||
@ -68,22 +68,13 @@ print_help (char *name)
|
||||
name);
|
||||
} /* print_help */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
union
|
||||
{
|
||||
double d;
|
||||
unsigned u;
|
||||
} now = { .d = jerry_port_get_current_time () };
|
||||
srand (now.u);
|
||||
if (argc <= 1 || (argc == 2 && (!strcmp ("-h", argv[1]) || !strcmp ("--help", argv[1]))))
|
||||
{
|
||||
print_help (argv[0]);
|
||||
return JERRY_STANDALONE_EXIT_CODE_OK;
|
||||
}
|
||||
/* Global "argc" and "argv" used to avoid argument passing via stack. */
|
||||
static int argc;
|
||||
static char **argv;
|
||||
|
||||
static JERRY_ATTR_NOINLINE int
|
||||
run (void)
|
||||
{
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
jerry_value_t ret_value = jerry_create_undefined ();
|
||||
|
||||
@ -120,16 +111,134 @@ main (int argc,
|
||||
ret_value = jerry_create_undefined ();
|
||||
}
|
||||
|
||||
int ret_code = JERRY_STANDALONE_EXIT_CODE_OK;
|
||||
|
||||
if (jerry_value_is_error (ret_value))
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unhandled exception: Script Error!\n");
|
||||
ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
|
||||
}
|
||||
int ret_code = !jerry_value_is_error (ret_value) ? JERRY_STANDALONE_EXIT_CODE_OK : JERRY_STANDALONE_EXIT_CODE_FAIL;
|
||||
|
||||
jerry_release_value (ret_value);
|
||||
jerry_cleanup ();
|
||||
|
||||
return ret_code;
|
||||
} /* run */
|
||||
|
||||
#if defined (JERRY_TEST_STACK_MEASURE) && (JERRY_TEST_STACK_MEASURE)
|
||||
|
||||
/**
|
||||
* How this stack measuring works:
|
||||
*
|
||||
* 1) Get the current stack pointer before doing the test execution.
|
||||
* This will be the "Stack bottom".
|
||||
* 2) Fill the stack towards lower addresses with a placeholder 32 bit value.
|
||||
* A "STACK_MEASURE_RANGE" big area will be filled with the value starting
|
||||
* from "Stack bottom".
|
||||
* The "Stack bottom" + "STACK_MEASURE_RANGE" will be the "Stack top".
|
||||
* 3) Run the tests.
|
||||
* 4) Check the stack backwards from "Stack top" to see where the 32 bit placeholder
|
||||
* value is not present. The point where the 32 bit value is not found is
|
||||
* considered to be the "Stack max". The "Stack bottom" - "Stack max" substraction
|
||||
* will give the stack usage in bytes.
|
||||
*
|
||||
*
|
||||
* Based on this the expected stack layout is:
|
||||
* The stack is expected to "grow" towards lower address.
|
||||
*
|
||||
* |-------|
|
||||
* | | <- low address - "Stack top"
|
||||
* |-------|
|
||||
* | |
|
||||
* |-------|
|
||||
* ....
|
||||
* |-------|
|
||||
* | | <- "Stack max"
|
||||
* |-------|
|
||||
* ....
|
||||
* |-------|
|
||||
* | | <- high address - "Stack bottom"
|
||||
* |-------|
|
||||
*
|
||||
*/
|
||||
|
||||
#if !(defined (__linux__) && __linux__)
|
||||
#error "Unsupported stack measurement platform!"
|
||||
#endif /* !(defined ( __linux__) && __linux__) */
|
||||
|
||||
#if defined (__x86_64__)
|
||||
#define STACK_SAVE(TARGET) { __asm volatile ("mov %%rsp, %0" : "=m" (TARGET)); }
|
||||
#elif defined (__i386__)
|
||||
#define STACK_SAVE(TARGET) { __asm volatile ("mov %%esp, %0" : "=m" (TARGET)); }
|
||||
#elif defined (__arm__)
|
||||
#define STACK_SAVE(TARGET) { __asm volatile ("mov %0, sp" : "=r" (TARGET)); }
|
||||
#else /* !defined (__x86_64__) && !defined (__i386__) && !defined (__arm__) */
|
||||
#error "Unsupported stack measurement target!"
|
||||
#endif /* !defined (__x86_64__) && !defined (__i386__) && !defined (__arm__) */
|
||||
|
||||
static void *g_stack_bottom = 0x0;
|
||||
|
||||
#define STACK_MEASURE_RANGE ((2 * 1024 * 1024))
|
||||
#define STACK_PATTERN (0xDEADBEEF)
|
||||
#define STACK_INIT(TARGET, SIZE) do \
|
||||
{ \
|
||||
for (size_t idx = 0; idx < (SIZE / sizeof (uint32_t)); idx++) \
|
||||
{ \
|
||||
((uint32_t*)(TARGET))[idx] = STACK_PATTERN; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STACK_USAGE(TARGET, SIZE) stack_usage (TARGET, SIZE)
|
||||
#define STACK_TOP_PTR(TARGET, SIZE) (uint32_t *) (((uint8_t *) TARGET) - SIZE)
|
||||
|
||||
static void
|
||||
stack_usage (uint32_t *stack_top_p, size_t length_in_bytes)
|
||||
{
|
||||
uint32_t *stack_bottom_p = stack_top_p + (length_in_bytes / sizeof (uint32_t));
|
||||
uint32_t *stack_p = stack_top_p;
|
||||
|
||||
while (stack_p < stack_bottom_p)
|
||||
{
|
||||
if (*stack_p != STACK_PATTERN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
stack_p++;
|
||||
}
|
||||
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Used stack: %d\n", (int) ((uint8_t *) stack_bottom_p - (uint8_t *) stack_p));
|
||||
} /* stack_usage */
|
||||
|
||||
#else /* (JERRY_TEST_STACK_MEASURE) && (JERRY_TEST_STACK_MEASURE) */
|
||||
#define STACK_SAVE(TARGET)
|
||||
#define STACK_INIT(TARGET, SIZE)
|
||||
#define STACK_USAGE(TARGET, SIZE)
|
||||
#endif /* #if defined (JERRY_TEST_STACK_MEASURE) && (JERRY_TEST_STACK_MEASURE) */
|
||||
|
||||
int main (int main_argc,
|
||||
char **main_argv)
|
||||
{
|
||||
union
|
||||
{
|
||||
double d;
|
||||
unsigned u;
|
||||
} now = { .d = jerry_port_get_current_time () };
|
||||
srand (now.u);
|
||||
|
||||
argc = main_argc;
|
||||
argv = main_argv;
|
||||
|
||||
if (argc <= 1 || (argc == 2 && (!strcmp ("-h", argv[1]) || !strcmp ("--help", argv[1]))))
|
||||
{
|
||||
print_help (argv[0]);
|
||||
return JERRY_STANDALONE_EXIT_CODE_OK;
|
||||
}
|
||||
|
||||
STACK_SAVE (g_stack_bottom);
|
||||
STACK_INIT (STACK_TOP_PTR (g_stack_bottom, STACK_MEASURE_RANGE), STACK_MEASURE_RANGE);
|
||||
|
||||
int result = run ();
|
||||
|
||||
STACK_USAGE (STACK_TOP_PTR (g_stack_bottom, STACK_MEASURE_RANGE), STACK_MEASURE_RANGE);
|
||||
|
||||
if (result == JERRY_STANDALONE_EXIT_CODE_FAIL)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unhandled exception: Script Error!\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* main */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user