From 74653dc98e955a2d94001fd1bbdbf6a5c46d43f1 Mon Sep 17 00:00:00 2001 From: Blebowski <34539154+Blebowski@users.noreply.github.com> Date: Sun, 26 Feb 2023 18:40:22 +0100 Subject: [PATCH] Add verbose option to Coverage Report generation. (#632) --- nvc.1 | 2 + src/nvc.c | 1 + src/rt/cover.c | 116 ++++++++++++++++++++++++++++++++++++------------- 3 files changed, 88 insertions(+), 31 deletions(-) diff --git a/nvc.1 b/nvc.1 index fc5b0eac..483d2da4 100644 --- a/nvc.1 +++ b/nvc.1 @@ -411,6 +411,8 @@ a single hierarchy in the code coverage report. Default value of .Ar limit is 5000. +.It Fl V , Fl -verbose +Prints detailed hierarchy coverage when generating code coverage report. .El .El .\" ------------------------------------------------------------ diff --git a/src/nvc.c b/src/nvc.c index a8aa3c0c..e8e2f14f 100644 --- a/src/nvc.c +++ b/src/nvc.c @@ -1087,6 +1087,7 @@ static int coverage(int argc, char **argv) { "merge", required_argument, 0, 'm' }, { "dont-print", required_argument, 0, 'd' }, { "item-limit", required_argument, 0, 'l' }, + { "verbose", no_argument, 0, 'V' }, { 0, 0, 0, 0 } }; diff --git a/src/rt/cover.c b/src/rt/cover.c index 020b49e2..20472cbf 100644 --- a/src/rt/cover.c +++ b/src/rt/cover.c @@ -57,6 +57,7 @@ typedef struct _cover_report_ctx cover_report_ctx_t; typedef struct _cover_file cover_file_t; typedef struct _cover_scope cover_scope_t; typedef struct _cover_exclude_ctx cover_exclude_ctx_t; +typedef struct _cover_rpt_buf cover_rpt_buf_t; typedef struct _cover_scope { ident_t name; @@ -68,19 +69,25 @@ typedef struct _cover_scope { int sig_pos; } cover_scope_t; +struct _cover_rpt_buf { + text_buf_t *tb; + cover_rpt_buf_t *prev; +}; + struct _cover_tagging { - int next_stmt_tag; - int next_branch_tag; - int next_toggle_tag; - int next_expression_tag; - int next_hier_tag; - ident_t hier; - tag_array_t tags; - cover_mask_t mask; - int array_limit; - int array_depth; - int report_item_limit; - cover_scope_t *top_scope; + int next_stmt_tag; + int next_branch_tag; + int next_toggle_tag; + int next_expression_tag; + int next_hier_tag; + ident_t hier; + tag_array_t tags; + cover_mask_t mask; + int array_limit; + int array_depth; + int report_item_limit; + cover_rpt_buf_t *rpt_buf; + cover_scope_t *top_scope; }; typedef struct { @@ -136,6 +143,7 @@ struct _cover_report_ctx { cover_chain_t ch_branch; cover_chain_t ch_toggle; cover_chain_t ch_expression; + int lvl; }; static cover_file_t *files; @@ -1281,10 +1289,16 @@ static void cover_print_timestamp(FILE *f) fprintf(f, ""); } -static void cover_print_hierarchy_summary(FILE *f, cover_stats_t *stats, ident_t hier, - bool top, bool full_hier) +static void cover_print_hierarchy_summary(FILE *f, cover_report_ctx_t *ctx, ident_t hier, + bool top, bool full_hier, bool flat) { ident_t print_hier = (full_hier) ? hier : ident_rfrom(hier, '.'); + cover_stats_t *stats; + + if (flat) + stats = &(ctx->flat_stats); + else + stats = &(ctx->nested_stats); fprintf(f, " \n" " %s\n", @@ -1304,37 +1318,62 @@ static void cover_print_hierarchy_summary(FILE *f, cover_stats_t *stats, ident_t fprintf(f, " \n"); + float perc_stmt = 0.0f; + float perc_branch = 0.0f; + float perc_toggle = 0.0f; + float perc_expr = 0.0f; + + if (stats->total_stmts > 0) + perc_stmt = 100.0 * ((float)stats->hit_stmts) / stats->total_stmts; + if (stats->total_branches > 0) + perc_branch = 100.0 * ((float)stats->hit_branches) / stats->total_branches; + if (stats->total_toggles > 0) + perc_toggle = 100.0 * ((float)stats->hit_toggles) / stats->total_toggles; + if (stats->total_expressions > 0) + perc_expr = 100.0 * ((float)stats->hit_expressions) / stats->total_expressions; + if (top) { notef("code coverage results for: %s", istr(hier)); - if (stats->total_stmts > 0) - notef(" statement: %.1f %% (%d/%d)", - 100.0 * ((double)stats->hit_stmts) / stats->total_stmts, + if (perc_stmt > 0) + notef(" statement: %.1f %% (%d/%d)", perc_stmt, stats->hit_stmts, stats->total_stmts); else notef(" statement: N.A."); - if (stats->total_branches > 0) - notef(" branch: %.1f %% (%d/%d)", - 100.0 * ((double)stats->hit_branches) / stats->total_branches, + if (perc_branch > 0) + notef(" branch: %.1f %% (%d/%d)", perc_branch, stats->hit_branches, stats->total_branches); else notef(" branch: N.A."); - if (stats->total_toggles > 0) - notef(" toggle: %.1f %% (%d/%d)", - 100.0 * ((double)stats->hit_toggles) / stats->total_toggles, + if (perc_toggle > 0) + notef(" toggle: %.1f %% (%d/%d)", perc_toggle, stats->hit_toggles, stats->total_toggles); else notef(" toggle: N.A."); - if (stats->total_expressions > 0) - notef(" expression: %.1f %% (%d/%d)", - 100.0 * ((double)stats->hit_expressions) / stats->total_expressions, + if (perc_expr > 0) + notef(" expression: %.1f %% (%d/%d)", perc_expr, stats->hit_expressions, stats->total_expressions); else notef(" expression: N.A."); } + else if (opt_get_int(OPT_VERBOSE) && !flat) { + + cover_rpt_buf_t *new = xcalloc(sizeof(cover_rpt_buf_t)); + new->tb = tb_new(); + new->prev = ctx->tagging->rpt_buf; + ctx->tagging->rpt_buf = new; + + tb_printf(new->tb, + "%*s %-*s %10.1f %% (%d/%d) %10.1f %% (%d/%d) %10.1f %% (%d/%d) %10.1f %% (%d/%d)", + ctx->lvl, "", 50-ctx->lvl, istr(ident_rfrom(ctx->start_tag->hier, '.')), + perc_stmt, stats->hit_stmts, stats->total_stmts, + perc_branch, stats->hit_branches, stats->total_branches, + perc_toggle, stats->hit_toggles, stats->total_toggles, + perc_expr, stats->hit_expressions, stats->total_expressions); + } } static void cover_print_code_line(FILE *f, loc_t loc, cover_line_t *line) @@ -1831,9 +1870,10 @@ static cover_tag_t* cover_report_hierarchy(cover_report_ctx_t *ctx, sub_ctx.start_tag = tag; sub_ctx.parent = ctx; sub_ctx.tagging = ctx->tagging; + sub_ctx.lvl = ctx->lvl + 2; tag = cover_report_hierarchy(&sub_ctx, dir); - cover_print_hierarchy_summary(f, &(sub_ctx.nested_stats), - tag->hier, false, false); + cover_print_hierarchy_summary(f, &sub_ctx, + tag->hier, false, false, false); // Add coverage from sub-hierarchies ctx->nested_stats.hit_stmts += sub_ctx.nested_stats.hit_stmts; @@ -1942,7 +1982,7 @@ static cover_tag_t* cover_report_hierarchy(cover_report_ctx_t *ctx, fprintf(f, "

Current Instance:

\n"); cover_print_hierarchy_header(f); - cover_print_hierarchy_summary(f, &(ctx->flat_stats), tag->hier, false, true); + cover_print_hierarchy_summary(f, ctx, tag->hier, false, true, true); cover_print_hierarchy_footer(f); fprintf(f, "

Details:

\n"); @@ -2003,10 +2043,24 @@ void cover_report(const char *path, cover_tagging_t *tagging, int item_limit) cover_print_html_header(f, &top_ctx, true, "NVC code coverage report"); cover_print_hierarchy_header(f); - cover_print_hierarchy_summary(f, &(top_ctx.nested_stats), - top_ctx.start_tag->hier, true, true); + cover_print_hierarchy_summary(f, &top_ctx, top_ctx.start_tag->hier, + true, true, false); cover_print_hierarchy_footer(f); cover_print_timestamp(f); + if (opt_get_int(OPT_VERBOSE)) { + notef("Coverage for sub-hierarchies:"); + printf("%-55s %-20s %-20s %-20s %-20s\n", + "Hierarchy", "Statement", "Branch", "Toggle", "Expression"); + cover_rpt_buf_t *buf = tagging->rpt_buf; + while (buf) { + printf("%s\n", tb_get(buf->tb)); + tb_free(buf->tb); + tagging->rpt_buf = buf->prev; + free(buf); + buf = tagging->rpt_buf; + }; + } + fclose(f); } -- 2.39.2