From 5daf210228ed176b4ef8bc84c027f03dc9b6a26f Mon Sep 17 00:00:00 2001 From: "Artem S. Povalyukhin" Date: Tue, 12 Nov 2019 16:07:42 +0300 Subject: [PATCH] Added support for labels in console.time(). This closes #248 issue on Github. --- src/njs_shell.c | 157 ++++++++++++++++++++++++++++++++++----- test/njs_expect_test.exp | 26 +++++-- 2 files changed, 157 insertions(+), 26 deletions(-) diff --git a/src/njs_shell.c b/src/njs_shell.c index b1e316c4..d0428ca6 100644 --- a/src/njs_shell.c +++ b/src/njs_shell.c @@ -56,13 +56,19 @@ typedef struct { } njs_ev_t; +typedef struct { + njs_value_t name; + uint64_t time; +} njs_timelabel_t; + + typedef struct { njs_vm_t *vm; njs_lvlhsh_t events; /* njs_ev_t * */ njs_queue_t posted_events; - uint64_t time; + njs_lvlhsh_t labels; /* njs_timelabel_t */ njs_completion_t completion; } njs_console_t; @@ -95,6 +101,8 @@ static njs_host_event_t njs_console_set_timer(njs_external_ptr_t external, static void njs_console_clear_timer(njs_external_ptr_t external, njs_host_event_t event); +static njs_int_t njs_timelabel_hash_test(njs_lvlhsh_query_t *lhq, void *data); + static njs_int_t lvlhsh_key_test(njs_lvlhsh_query_t *lhq, void *data); static void *lvlhsh_pool_alloc(void *pool, size_t size); static void lvlhsh_pool_free(void *pool, void *p, size_t size); @@ -170,6 +178,14 @@ static const njs_lvlhsh_proto_t lvlhsh_proto njs_aligned(64) = { }; +static const njs_lvlhsh_proto_t njs_timelabel_hash_proto njs_aligned(64) = { + NJS_LVLHSH_DEFAULT, + njs_timelabel_hash_test, + lvlhsh_pool_alloc, + lvlhsh_pool_free, +}; + + static njs_vm_ops_t njs_console_ops = { njs_console_set_timer, njs_console_clear_timer @@ -391,7 +407,7 @@ njs_console_init(njs_vm_t *vm, njs_console_t *console) njs_lvlhsh_init(&console->events); njs_queue_init(&console->posted_events); - console->time = UINT64_MAX; + njs_lvlhsh_init(&console->labels); console->completion.completions = njs_vm_completions(vm, NULL); if (console->completion.completions == NULL) { @@ -1010,23 +1026,75 @@ njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } +static const njs_value_t njs_default_label = njs_string("default"); + + static njs_int_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - njs_console_t *console; + njs_int_t ret; + njs_console_t *console; + njs_value_t *value; + njs_timelabel_t *label; + njs_str_t name; + njs_lvlhsh_query_t lhq; - if (!njs_value_is_undefined(njs_arg(args, nargs, 1))) { - njs_vm_error(vm, "labels not implemented"); + console = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (njs_slow_path(console == NULL)) { return NJS_ERROR; } - console = njs_vm_external(vm, njs_arg(args, nargs, 0)); - if (njs_slow_path(console == NULL)) { + value = njs_arg(args, nargs, 1); + + if (njs_slow_path(!njs_is_string(value))) { + if (njs_is_undefined(value)) { + value = njs_value_arg(&njs_default_label); + + } else { + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + } + + njs_string_get(value, &name); + + label = njs_mp_alloc(vm->mem_pool, sizeof(njs_timelabel_t)); + if (njs_slow_path(label == NULL)) { + njs_memory_error(vm); return NJS_ERROR; } - console->time = njs_time(); + lhq.replace = 0; + lhq.key = name; + lhq.key_hash = njs_djb_hash(name.start, name.length); + lhq.value = label; + lhq.pool = vm->mem_pool; + lhq.proto = &njs_timelabel_hash_proto; + + ret = njs_lvlhsh_insert(&console->labels, &lhq); + + if (njs_fast_path(ret == NJS_OK)) { + /* GC: retain. */ + label->name = *value; + + } else { + njs_mp_free(vm->mem_pool, label); + + if (njs_slow_path(ret == NJS_ERROR)) { + njs_internal_error(vm, "lvlhsh insert failed"); + + return NJS_ERROR; + } + + njs_printf("Timer \"%V\" already exists.\n", &name); + + label = lhq.value; + } + + label->time = njs_time(); njs_set_undefined(&vm->retval); @@ -1038,34 +1106,66 @@ static njs_int_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - uint64_t ns, ms; - njs_console_t *console; + uint64_t ns, ms; + njs_int_t ret; + njs_console_t *console; + njs_value_t *value; + njs_timelabel_t *label; + njs_str_t name; + njs_lvlhsh_query_t lhq; ns = njs_time(); - if (!njs_value_is_undefined(njs_arg(args, nargs, 1))) { - njs_vm_error(vm, "labels not implemented"); - return NJS_ERROR; - } - console = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (njs_slow_path(console == NULL)) { return NJS_ERROR; } - if (njs_fast_path(console->time != UINT64_MAX)) { + value = njs_arg(args, nargs, 1); + + if (njs_slow_path(!njs_is_string(value))) { + if (njs_is_undefined(value)) { + value = njs_value_arg(&njs_default_label); + + } else { + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + } + + njs_string_get(value, &name); + + lhq.key = name; + lhq.key_hash = njs_djb_hash(name.start, name.length); + lhq.pool = vm->mem_pool; + lhq.proto = &njs_timelabel_hash_proto; - ns = ns - console->time; + ret = njs_lvlhsh_delete(&console->labels, &lhq); + + if (njs_fast_path(ret == NJS_OK)) { + + label = lhq.value; + + ns = ns - label->time; ms = ns / 1000000; ns = ns % 1000000; - njs_printf("default: %uL.%06uLms\n", ms, ns); + njs_printf("%V: %uL.%06uLms\n", &name, ms, ns); - console->time = UINT64_MAX; + /* GC: release. */ + njs_mp_free(vm->mem_pool, label); } else { - njs_printf("Timer \"default\" doesn’t exist.\n"); + if (ret == NJS_ERROR) { + njs_internal_error(vm, "lvlhsh delete failed"); + + return NJS_ERROR; + } + + njs_printf("Timer \"%V\" doesn’t exist.\n", &name); } njs_set_undefined(&vm->retval); @@ -1152,6 +1252,23 @@ njs_console_clear_timer(njs_external_ptr_t external, njs_host_event_t event) } +static njs_int_t +njs_timelabel_hash_test(njs_lvlhsh_query_t *lhq, void *data) +{ + njs_timelabel_t *label; + njs_str_t str; + + label = data; + njs_string_get(&label->name, &str); + + if (njs_strstr_eq(&lhq->key, &str)) { + return NJS_OK; + } + + return NJS_DECLINED; +} + + static njs_int_t lvlhsh_key_test(njs_lvlhsh_query_t *lhq, void *data) { diff --git a/test/njs_expect_test.exp b/test/njs_expect_test.exp index 04cc3f6a..ca227d1f 100644 --- a/test/njs_expect_test.exp +++ b/test/njs_expect_test.exp @@ -225,16 +225,30 @@ njs_test { njs_test { {"console.time()\r\n" "console.time()\r\nundefined\r\n>> "} - {"console.time(undefined)\r\n" - "console.time(undefined)\r\nundefined\r\n>> "} {"console.timeEnd()\r\n" "console.timeEnd()\r\ndefault: *.*ms\r\nundefined\r\n>> "} - {"console.time('a')\r\n" - "console.time('a')\r\nError: labels not implemented"} - {"console.timeEnd('a')\r\n" - "console.timeEnd('a')\r\nError: labels not implemented"} + {"console.time(undefined)\r\n" + "console.time(undefined)\r\nundefined\r\n>> "} + {"console.timeEnd(undefined)\r\n" + "console.timeEnd(undefined)\r\ndefault: *.*ms\r\nundefined\r\n>> "} + {"console.time('abc')\r\n" + "console.time('abc')\r\nundefined\r\n>> "} + {"console.time('abc')\r\n" + "console.time('abc')\r\nTimer \"abc\" already exists.\r\nundefined\r\n>> "} + {"console.timeEnd('abc')\r\n" + "console.timeEnd('abc')\r\nabc: *.*ms\r\nundefined\r\n>> "} + {"console.time(true)\r\n" + "console.time(true)\r\nundefined\r\n>> "} + {"console.timeEnd(true)\r\n" + "console.timeEnd(true)\r\ntrue: *.*ms\r\nundefined\r\n>> "} + {"console.time(42)\r\n" + "console.time(42)\r\nundefined\r\n>> "} + {"console.timeEnd(42)\r\n" + "console.timeEnd(42)\r\n42: *.*ms\r\nundefined\r\n>> "} {"console.timeEnd()\r\n" "console.timeEnd()\r\nTimer \"default\" doesn’t exist."} + {"console.timeEnd('abc')\r\n" + "console.timeEnd('abc')\r\nTimer \"abc\" doesn’t exist."} } njs_test { -- 2.47.3