[njs] Added support for labels in console.time().

Dmitry Volyntsev xeioex at nginx.com
Wed Nov 13 16:33:00 UTC 2019


details:   https://hg.nginx.org/njs/rev/3e9e1de11557
branches:  
changeset: 1237:3e9e1de11557
user:      Artem S. Povalyukhin <artem.povaluhin at gmail.com>
date:      Tue Nov 12 16:07:42 2019 +0300
description:
Added support for labels in console.time().

This closes #248 issue on Github.

diffstat:

 src/njs_shell.c          |  159 ++++++++++++++++++++++++++++++++++++++++------
 test/njs_expect_test.exp |   26 +++++-
 2 files changed, 158 insertions(+), 27 deletions(-)

diffs (282 lines):

diff -r 077e125e31c1 -r 3e9e1de11557 src/njs_shell.c
--- a/src/njs_shell.c	Wed Nov 13 18:27:06 2019 +0300
+++ b/src/njs_shell.c	Tue Nov 12 16:07:42 2019 +0300
@@ -57,12 +57,18 @@ typedef struct {
 
 
 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_
 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_
 };
 
 
+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_conso
     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_v
 }
 
 
+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;
-
-    if (!njs_value_is_undefined(njs_arg(args, nargs, 1))) {
-        njs_vm_error(vm, "labels not implemented");
-        return NJS_ERROR;
-    }
+    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;
 
     console = njs_vm_external(vm, njs_arg(args, nargs, 0));
     if (njs_slow_path(console == NULL)) {
         return NJS_ERROR;
     }
 
-    console->time = njs_time();
+    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;
+    }
+
+    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;
+            }
+        }
+    }
 
-        ns = ns - console->time;
+    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;
+
+    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);
@@ -1153,6 +1253,23 @@ njs_console_clear_timer(njs_external_ptr
 
 
 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)
 {
     njs_ev_t  *ev;
diff -r 077e125e31c1 -r 3e9e1de11557 test/njs_expect_test.exp
--- a/test/njs_expect_test.exp	Wed Nov 13 18:27:06 2019 +0300
+++ b/test/njs_expect_test.exp	Tue Nov 12 16:07:42 2019 +0300
@@ -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 {


More information about the nginx-devel mailing list