From 8d05432e98a65fb22e81b36867da0e9eb3bba737 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 3 Jun 2024 09:52:53 +0200 Subject: [PATCH] CLI: Improved and renamed show statistics -> show memory command Fixed shared yang-spec reference count --- apps/cli/cli_show.c | 186 +++++++++++++++++++++++------ example/README.md | 2 +- example/main/example_cli.cli | 10 +- lib/src/clixon_yang_schema_mount.c | 41 +++---- 4 files changed, 179 insertions(+), 60 deletions(-) diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 1460654bb..1638fbbdc 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -1816,7 +1816,20 @@ clixon_cli2cbuf(clixon_handle h, return retval; } -/*! CLI callback show statistics +/*! CLI callback show memory statistics (and numbers) + * + * mempry in KiB + * @param[in] h Clixon handle + * @param[in] cvv Vector of cli string and instantiated variables + * @param[in] argv Arguments given at the callback: [(cli|backend) [detail]] + * @retval 0 OK + * @retval -1 Error + * where level means: + * : Show mounts and summary clispec + * cli : Show mounts and summary clispec + * cli detail : Show mounts and per parse-tree clispec + * backend : Show summary mem + * backend detail : Per-module */ int cli_show_statistics(clixon_handle h, @@ -1827,57 +1840,158 @@ cli_show_statistics(clixon_handle h, cbuf *cb = NULL; cxobj *xret = NULL; cxobj *xerr; - cg_var *cv; - int modules = 0; + char *what = NULL; + int detail = 0; pt_head *ph; parse_tree *pt; - uint64_t nr = 0; - size_t sz = 0; + uint64_t nr; + uint64_t tnr; + size_t sz; + size_t tsz; + yang_stmt *yspec; + yang_stmt *yspec1; + yang_stmt *yspec2; + yang_stmt *ymnt; + cvec *cvv1 = NULL; + cvec *cvv2; + cg_var *cv; + cg_var *cv2; + cg_var *cv3; - if (argv != NULL && cvec_len(argv) != 1){ - clixon_err(OE_PLUGIN, EINVAL, "Expected arguments: [modules]"); + if (argv != NULL && (cvec_len(argv) < 1 || cvec_len(argv) > 2)){ + clixon_err(OE_PLUGIN, EINVAL, "Expected arguments: [(cli|backend) [detail]]"); goto done; } + yspec = clicon_dbspec_yang(h); if (argv){ cv = cvec_i(argv, 0); - modules = (strcmp(cv_string_get(cv), "modules") == 0); + what = cv_string_get(cv); + if (strcmp(what, "cli") != 0 && strcmp(what, "backend") != 0){ + clixon_err(OE_PLUGIN, EINVAL, "Unexpected argument: %s, expected: cli|backend", what); + goto done; + } + if (cvec_len(argv) > 1 && + (cv = cvec_i(argv, 1)) != NULL){ + if (strcmp(cv_string_get(cv), "detail") != 0){ + clixon_err(OE_PLUGIN, EINVAL, "Unexpected argument: %s, expected: detail", + cv_string_get(cv)); + goto done; + } + detail = 1; + } } + else + what = "cli"; if ((cb = cbuf_new()) == NULL){ clixon_err(OE_PLUGIN, errno, "cbuf_new"); goto done; } - /* CLI */ - cligen_output(stdout, "CLI:\n"); - ph = NULL; - while ((ph = cligen_ph_each(cli_cligen(h), ph)) != NULL) { - if ((pt = cligen_ph_parsetree_get(ph)) == NULL) - continue; + if (strcmp(what, "cli") == 0) { + /* CLI */ + if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT")) + cligen_output(stdout, "%-25s %-8s %-10s %-8s %-8s\n", "YANG", "Nodes#", "Mem(KiB)", "Refs", "Pointer"); + else + cligen_output(stdout, "%-25s %-8s %-10s\n", "YANG", "Nodes#", "Mem(KiB)"); nr = 0; sz = 0; - pt_stats(pt, &nr, &sz); - cligen_output(stdout, "%s: nr=%" PRIu64 " size:%zu\n", - cligen_ph_name_get(ph), nr, sz); - } - /* Backend */ - cprintf(cb, ""); - cprintf(cb, "", CLIXON_LIB_NS); - if (modules) - cprintf(cb, "true"); - cprintf(cb, ""); - cprintf(cb, ""); - if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, NULL) < 0) - goto done; - if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_err_netconf(h, OE_NETCONF, 0, xerr, "Get configuration"); - goto done; + if (yang_stats(yspec, &nr, &sz) < 0) + goto done; + tnr = nr; + tsz = sz; + cligen_output(stdout, "%-25s %-8" PRIu64 " %-8zu\n", "Top-level", nr, sz/1024); + if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT")) { + if (yang_mount_yspec2ymnt(yspec, &cvv1) < 0) + goto done; + cv = NULL; + while ((cv = cvec_each(cvv1, cv)) != NULL) { + ymnt = cv_void_get(cv); + if ((cvv2 = yang_cvec_get(ymnt)) != NULL){ + cv2 = NULL; + while ((cv2 = cvec_each(cvv2, cv2)) != NULL) { + yspec1 = cv_void_get(cv2); + nr = 0; sz = 0; + if (yang_stats(yspec1, &nr, &sz) < 0) + goto done; + /* check if not duplicate */ + cv3 = NULL; + while ((cv3 = cvec_each(cvv2, cv3)) != NULL) { + if (cv2 == cv3) + break; + yspec2 = cv_void_get(cv3); + if (yspec1 == yspec2) + break; + } + if (cv2 != cv3){ + cligen_output(stdout, "%s \\\n", cv_name_get(cv2)); + } + else { + tnr += nr; + tsz += sz; + if (strlen(cv_name_get(cv2)) > 25){ + cligen_output(stdout, "%s \\\n", cv_name_get(cv2)); + cligen_output(stdout, "%-25s %-8" PRIu64 " %-10zu %-8d %-8p\n", + "", + nr, sz/1024, + yang_ref_get(yspec1), ymnt); + } + else + cligen_output(stdout, "%-25s %-8" PRIu64 " %-10zu %-8d %-8p\n", + cv_name_get(cv2), + nr, sz/1024, + yang_ref_get(yspec1), ymnt); + } + } + } + } + } + cligen_output(stdout, "%-25s %-8" PRIu64 " %-8zu\n", "YANG Total", tnr, tsz/1024); + } + if (strcmp(what, "cli") == 0) { + cligen_output(stdout, "%-25s %-8s %-8s\n", "CLIspecs", "Nodes#", "Mem(KiB)"); + tnr = 0; + tsz = 0; + ph = NULL; + while ((ph = cligen_ph_each(cli_cligen(h), ph)) != NULL) { + if ((pt = cligen_ph_parsetree_get(ph)) == NULL) + continue; + nr = 0; sz = 0; + pt_stats(pt, &nr, &sz); + tnr += nr; + tsz += sz; + if (detail){ + if (strlen(cligen_ph_name_get(ph)) > 25){ + cligen_output(stdout, "%s \\\n", cligen_ph_name_get(ph)); + cligen_output(stdout, "%-25s %-8" PRIu64 " %-8zu\n", "", nr, sz/1024); + } + else + cligen_output(stdout, "%-25s %-8" PRIu64 " %-8zu\n", cligen_ph_name_get(ph), nr, sz/1024); + } + } + cligen_output(stdout, "%-25s %-8" PRIu64 " %-8zu\n", "CLIspec Total", tnr, tsz/1024); + } + if (strcmp(what, "backend") == 0) { + /* Backend */ + cprintf(cb, ""); + cprintf(cb, "", CLIXON_LIB_NS); + if (detail) + cprintf(cb, "true"); + cprintf(cb, ""); + cprintf(cb, ""); + if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, NULL) < 0) + goto done; + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ + clixon_err_netconf(h, OE_NETCONF, 0, xerr, "Get configuration"); + goto done; + } + cligen_output(stdout, "Backend (nr nodes, size of mem\n"); + if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 1, NULL, cligen_output, 0, 1) < 0) + goto done; } - fprintf(stdout, "Backend:\n"); - if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 1, NULL, cligen_output, 0, 1) < 0) - goto done; - fprintf(stdout, "CLI:\n"); retval = 0; done: + if (cvv1) + cvec_free(cvv1); if (xret) xml_free(xret); if (cb) diff --git a/example/README.md b/example/README.md index 020e9afe0..3854f7fc4 100644 --- a/example/README.md +++ b/example/README.md @@ -3,7 +3,7 @@ See also the separate [clixon-examples](https://github.com/clicon/clixon-examples) repo -The only Clixon example remaining is for internal testing: +The remaining Clixon example is for internal testing: * [Main example](main/README.md) diff --git a/example/main/example_cli.cli b/example/main/example_cli.cli index 500027d0c..4a45b8dc0 100644 --- a/example/main/example_cli.cli +++ b/example/main/example_cli.cli @@ -123,9 +123,13 @@ show("Show a particular state of the system"){ yang("Show yang specs"), show_yang(); { clixon-example("Show clixon-example yang spec"), show_yang("clixon-example"); } - statistics("Show statistics"), cli_show_statistics();{ - brief, cli_show_statistics(); - modules, cli_show_statistics("modules"); + memory("Show memory usage") { + cli("Show CLI memory usage"), cli_show_statistics("cli");{ + detail("Show detailed CLI memory usage"), cli_show_statistics("cli", "detail"); + } + backend("Show backend memory usage"), cli_show_statistics("backend");{ + detail("Show detailed backend memory usage"), cli_show_statistics("backend", "detail"); + } } } diff --git a/lib/src/clixon_yang_schema_mount.c b/lib/src/clixon_yang_schema_mount.c index 89efcea13..bbfdd4b7c 100644 --- a/lib/src/clixon_yang_schema_mount.c +++ b/lib/src/clixon_yang_schema_mount.c @@ -195,7 +195,7 @@ yang_mount_get(yang_stmt *y, cg_var *cv; clixon_debug(CLIXON_DBG_YANG | CLIXON_DBG_DETAIL, "%s %p", xpath, y); - if ((cvv = yang_cvec_get(y)) != NULL && + if ((cvv = yang_cvec_get(y)) != NULL && (cv = cvec_find(cvv, xpath)) != NULL && yspec) *yspec = cv_void_get(cv); @@ -260,6 +260,7 @@ yang_mount_set(yang_stmt *y, #if 0 /* Problematic to free yang specs here, upper layers should handle it? */ ys_free(yspec0); #endif + yang_ref_dec(yspec0); cv_void_set(cv, NULL); } else if ((cv = yang_cvec_add(y, CGV_VOID, xpath)) == NULL) @@ -275,6 +276,7 @@ yang_mount_set(yang_stmt *y, /* tag yspec with key/xpath */ yang_cv_set(yspec, cv2); cv_void_set(cv, yspec); + yang_ref_inc(yspec); /* share */ yang_flag_set(y, YANG_FLAG_MOUNTPOINT); /* Cache value */ retval = 0; done: @@ -424,14 +426,15 @@ int yang_mount_freeall(yang_stmt *ymnt) { cvec *cvv; - cg_var *cv = NULL; + cg_var *cv; yang_stmt *ys; - cvv = yang_cvec_get(ymnt); - cv = NULL; - while ((cv = cvec_each(cvv, cv)) != NULL){ - if ((ys = cv_void_get(cv)) != NULL) - ys_free(ys); + if ((cvv = yang_cvec_get(ymnt)) != NULL){ + cv = NULL; + while ((cv = cvec_each(cvv, cv)) != NULL){ + if ((ys = cv_void_get(cv)) != NULL) + ys_free(ys); + } } return 0; } @@ -498,25 +501,24 @@ yang_mount_xtop2xmnt(cxobj *xtop, return retval; } -/*! Find schema mounts - callback function for xml_apply +/*! Find schema mounts - callback function for yang_apply * - * @param[in] y YANG node - * @param[in] arg cvec, if match add node - * @retval 2 Locally abort this subtree, continue with others - * @retval 1 Abort, dont continue with others, return 1 to end user - * @retval 0 OK, continue - * @retval -1 Error, aborted at first error encounter, return -1 to end user + * @param[in] yn yang node + * @param[in] arg Argument + * @retval n OK, abort traversal and return to caller with "n" + * @retval 0 OK, continue with next + * @retval -1 Error, abort */ static int find_yang_schema_mounts(yang_stmt *y, void *arg) { - int ret; - cvec *cvv = (cvec *)arg; - cg_var *cv; + int ret; + cvec *cvv = (cvec *)arg; + cg_var *cv; if (yang_config(y) == 0) - return 2; + return 0; if ((ret = yang_schema_mount_point(y)) < 0) return -1; if (ret == 0) @@ -890,7 +892,7 @@ yang_schema_cmp_kludge(clixon_handle h, * 8. set as new * @param[in] h Clixon handle * @param[in] xt XML tree node - * @retval 0 OK + * @retval 0 OK * @retval -1 Error */ static int @@ -937,7 +939,6 @@ yang_schema_find_share(clixon_handle h, if ((ret = yang_schema_cmp_kludge(h, xyanglib, xmodst)) < 0) goto done; if (ret == 1){ /* equal */ - yang_ref_inc(yspec1); /* share */ *yspecp = yspec1; break; }