Lines Matching +full:enum +full:- +full:cnt +full:- +full:name

1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
39 enum stat_id {
57 NUM_STATS_CNT = FILE_NAME - VERDICT,
61 * - A side value;
62 * - B side value;
63 * - absolute diff value;
64 * - relative (percentage) diff value.
69 * - `_a` for A side value;
70 * - `_b` for B side value;
71 * - `_diff` for absolute diff value;
72 * - `_pct` for relative (percentage) diff value.
79 * --------- --------- --------------
80 * 21547 20920 -627 (-2.91%)
83 * - 21547 is A side value (insns_a);
84 * - 20920 is B side value (insns_b);
85 * - -627 is absolute diff value (insns_diff);
86 * - -2.91% is relative diff value (insns_pct).
89 * For file and program name, _a and _b variants are equivalent and there are
92 enum stat_variant {
117 enum stat_id ids[ALL_STATS_CNT];
118 enum stat_variant variants[ALL_STATS_CNT];
124 enum resfmt {
126 RESFMT_TABLE_CALCLEN, /* fake format to pre-calculate table's column widths */
130 enum filter_kind {
135 enum operator_kind {
145 enum filter_kind kind;
151 enum operator_kind op;
153 enum stat_variant stat_var;
159 char *name;
160 enum { INTEGRAL, ENUMERATOR } type;
176 enum resfmt out_fmt;
213 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
231 "USAGE: veristat <obj-file> [<obj-file>...]\n"
232 " OR: veristat -C <baseline.csv> <comparison.csv>\n"
233 " OR: veristat -R <results.csv>\n"
234 " OR: veristat -vl2 <to_analyze.bpf.o>\n";
236 enum {
246 { "log-level", 'l', "LEVEL", 0, "Verifier log level (default 0 for normal mode, 1 for verbose mode, 2 for full verification log)" },
247 { "log-fixed", OPT_LOG_FIXED, NULL, 0, "Disable verifier log rotation" },
248 { "log-size", OPT_LOG_SIZE, "BYTES", 0, "Customize verifier log size (default to 16MB)" },
249 { "top-n", 'n', "N", 0, "Emit only up to first N results." },
253 { "output-format", 'o', "FMT", 0, "Result output format (table, csv), default is table." },
257 { "test-states", 't', NULL, 0,
259 { "test-reg-invariants", 'r', NULL, 0,
261 { "top-src-lines", 'S', "N", 0, "Emit N most frequent source code lines" },
262 { "set-global-vars", 'G', "GLOBAL", 0, "Set global variables provided in the expression, for example \"var1 = 1\"" },
267 static int append_filter(struct filter **filters, int *cnt, const char *str);
269 static int append_var_preset(struct var_preset **presets, int *cnt, const char *expr);
312 return -EINVAL;
431 int fd, err = -EINVAL;
450 if (!ehdr || ehdr->e_type != ET_REL || (ehdr->e_machine && ehdr->e_machine != EM_BPF))
468 if (f->kind != FILTER_NAME)
471 if (f->any_glob && glob_matches(filename, f->any_glob))
473 if (f->any_glob && prog_name && glob_matches(prog_name, f->any_glob))
475 if (f->file_glob && glob_matches(filename, f->file_glob))
477 if (f->prog_glob && prog_name && glob_matches(prog_name, f->prog_glob))
483 if (f->kind != FILTER_NAME)
487 if (f->any_glob) {
488 if (glob_matches(filename, f->any_glob))
490 /* If we don't know program name yet, any_glob filter
493 * BPF object file, at which point program name will
496 if (!prog_name || glob_matches(prog_name, f->any_glob))
499 if (f->file_glob && !glob_matches(filename, f->file_glob))
501 if (f->prog_glob && prog_name && !glob_matches(prog_name, f->prog_glob))
507 /* if there are no file/prog name allow filters, allow all progs,
514 enum operator_kind op_kind;
531 static bool parse_stat_id_var(const char *name, size_t len, int *id,
532 enum stat_variant *var, bool *is_abs);
534 static int append_filter(struct filter **filters, int *cnt, const char *str)
541 tmp = realloc(*filters, (*cnt + 1) * sizeof(**filters));
543 return -ENOMEM;
546 f = &(*filters)[*cnt];
551 * - <stat> is one of supported numerical stats (verdict is also
553 * - <op> is comparison operator (see `operators` definitions);
554 * - <value> is an integer (or failure/success, or false/true as
560 enum stat_variant var;
572 if (!parse_stat_id_var(str, p - str, &id, &var, &is_abs)) {
573 fprintf(stderr, "Unrecognized stat name in '%s'!\n", str);
574 return -EINVAL;
577 fprintf(stderr, "Non-integer stat is specified in '%s'!\n", str);
578 return -EINVAL;
603 return -EINVAL;
607 f->kind = FILTER_STAT;
608 f->stat_id = id;
609 f->stat_var = var;
610 f->op = operators[i].op_kind;
611 f->abs = true;
612 f->value = val;
614 *cnt += 1;
619 * '<file-glob>/<prog-glob>'. In the former case <glob> is applied to
621 * practice. If user needs full control, they can use '/<prog-glob>'
622 * form to glob just program name, or '<file-glob>/' to glob only file
623 * name. But usually common <glob> seems to be the most useful and
626 f->kind = FILTER_NAME;
629 f->any_glob = strdup(str);
630 if (!f->any_glob)
631 return -ENOMEM;
634 /* non-empty file glob */
635 f->file_glob = strndup(str, p - str);
636 if (!f->file_glob)
637 return -ENOMEM;
640 /* non-empty prog glob */
641 f->prog_glob = strdup(p + 1);
642 if (!f->prog_glob) {
643 free(f->file_glob);
644 f->file_glob = NULL;
645 return -ENOMEM;
650 *cnt += 1;
662 err = -errno;
663 fprintf(stderr, "Failed to open filters in '%s': %s\n", path, strerror(-err));
699 return -ENOMEM;
703 return -ENOMEM;
716 err = -errno;
786 static bool parse_stat_id_var(const char *name, size_t len, int *id,
787 enum stat_variant *var, bool *is_abs)
799 if (len > 2 && name[0] == '|' && name[len - 1] == '|') {
801 name += 1;
802 len -= 2;
811 alias = def->names[j];
816 if (strncmp(name, alias, alias_len) != 0)
823 * non-comparison mode.
835 if (strncmp(name + alias_len, var_sfxs[k], sfx_len) == 0) {
836 *var = (enum stat_variant)k;
862 enum stat_variant var;
864 if (specs->spec_cnt >= ARRAY_SIZE(specs->ids)) {
865 fprintf(stderr, "Can't specify more than %zd stats\n", ARRAY_SIZE(specs->ids));
866 return -E2BIG;
869 if (len > 1 && (is_asc_sym(stat_name[len - 1]) || is_desc_sym(stat_name[len - 1]))) {
871 is_asc = is_asc_sym(stat_name[len - 1]);
872 len -= 1;
876 fprintf(stderr, "Unrecognized stat name '%s'\n", stat_name);
877 return -ESRCH;
880 specs->ids[specs->spec_cnt] = id;
881 specs->variants[specs->spec_cnt] = var;
882 specs->asc[specs->spec_cnt] = has_order ? is_asc : stat_defs[id].asc_by_default;
883 specs->abs[specs->spec_cnt] = is_abs;
884 specs->spec_cnt++;
892 int err, cnt = 0;
896 return -ENOMEM;
898 while ((next = strtok_r(cnt++ ? NULL : input, ",", &state))) {
931 int pos, lines, sub_stack, cnt = 0;
934 buf[buf_sz - 1] = '\0';
936 for (pos = strlen(buf) - 1, lines = 0; pos >= 0 && lines < MAX_PARSED_LOG_LINES; lines++) {
938 for (cur = &buf[pos]; cur > buf && cur[0] != '\n'; cur--, pos--) {
941 pos--;
948 if (1 == sscanf(cur, "verification time %ld usec\n", &s->stats[DURATION]))
951 &s->stats[TOTAL_INSNS],
952 &s->stats[MAX_STATES_PER_INSN],
953 &s->stats[TOTAL_STATES],
954 &s->stats[PEAK_STATES],
955 &s->stats[MARK_READ_MAX_LEN]))
961 while ((token = strtok_r(cnt++ ? NULL : stack, "+", &state))) {
964 s->stats[STACK] += sub_stack;
971 int cnt;
987 if (a_cnt->cnt != b_cnt->cnt)
988 return a_cnt->cnt > b_cnt->cnt ? -1 : 1;
989 return strcmp(a_cnt->line, b_cnt->line);
1016 err = -ENOMEM;
1032 err = -ENOMEM;
1037 cur->line = lines[0];
1038 cur->cnt = 1;
1040 if (strcmp(lines[i], cur->line) != 0) {
1042 cur->line = lines[i];
1043 cur->cnt = 0;
1045 cur->cnt++;
1047 unique_lines = cur - freq + 1;
1064 split--;
1069 printf("%5d: (%s)\t%s\n", freq[i].cnt, src_line, src_code);
1071 printf("%5d: %s\n", freq[i].cnt, src_code);
1082 enum bpf_prog_type *prog_type,
1083 enum bpf_attach_type *attach_type)
1090 * Just in case, we support both UAPI-side type names and
1091 * kernel-internal names.
1096 enum bpf_prog_type prog_type;
1097 enum bpf_attach_type attach_type;
1115 * to match on that, probably; so NULL for kern-side type
1122 return -EINVAL;
1133 return -ESRCH;
1159 mt = btf__type_by_id(btf, m->type);
1162 moff = m->offset / 8;
1203 enum bpf_prog_type prog_type;
1204 enum bpf_attach_type attach_type;
1214 t = btf__type_by_id(btf, t->type);
1221 t = btf__type_by_id(btf, t->type);
1224 t = btf__type_by_id(btf, t->type);
1226 t = btf__type_by_id(btf, t->type);
1230 ctx_name = btf__name_by_offset(btf, t->name_off);
1243 fprintf(stderr, "Failed to guess program type for freplace program with context type name '%s' for %s/%s. Consider using canonical type names to help veristat...\n",
1262 .log_buf = (void *)-1,
1273 if (ret == -EFAULT)
1275 else /* ret == -EINVAL, big log size is not supported by the verifier */
1301 return -ENOMEM;
1310 return -ENOMEM;
1313 /* --top-src-lines needs verifier log */
1338 stats->file_name = strdup(base_filename);
1339 stats->prog_name = strdup(bpf_program__name(prog));
1340 stats->stats[VERDICT] = err == 0; /* 1 - success, 0 - failure */
1341 stats->stats[SIZE] = bpf_program__insn_cnt(prog);
1342 stats->stats[PROG_TYPE] = bpf_program__type(prog);
1343 stats->stats[ATTACH_TYPE] = bpf_program__expected_attach_type(prog);
1348 stats->stats[JITED_SIZE] = info.jited_prog_len;
1354 filename, prog_name, stats->stats[DURATION],
1358 print_top_src_lines(buf, buf_sz, stats->prog_name);
1366 static int append_var_preset(struct var_preset **presets, int *cnt, const char *expr)
1374 tmp = realloc(*presets, (*cnt + 1) * sizeof(**presets));
1376 return -ENOMEM;
1378 cur = &(*presets)[*cnt];
1380 (*cnt)++;
1384 return -EINVAL;
1387 if (val[0] == '-' || isdigit(val[0])) {
1397 return -EINVAL;
1399 cur->ivalue = value;
1400 cur->type = INTEGRAL;
1402 /* if not a number, consider it enum value */
1403 cur->svalue = strdup(val);
1404 if (!cur->svalue)
1405 return -ENOMEM;
1406 cur->type = ENUMERATOR;
1409 cur->name = strdup(var);
1410 if (!cur->name)
1411 return -ENOMEM;
1424 err = -errno;
1425 fprintf(stderr, "Failed to open presets in '%s': %s\n", filename, strerror(-err));
1426 return -EINVAL;
1460 const char *cur_name = btf__name_by_offset(btf, e->name_off);
1463 *retval = e->val;
1472 const char *cur_name = btf__name_by_offset(btf, e->name_off);
1481 return -EINVAL;
1499 return -EINVAL;
1507 tid = btf__resolve_type(btf, member->type);
1509 return -EINVAL;
1512 if (member->name_off) {
1513 const char *name = btf__name_by_offset(btf, member->name_off);
1515 if (strcmp(member_name, name) == 0) {
1518 name);
1519 return -EINVAL;
1521 *member_offset = parent_offset + member->offset;
1528 err = btf_find_member(btf, member_type, parent_offset + member->offset,
1535 return -EINVAL;
1544 char *name;
1547 base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type));
1551 while ((name = strtok_r(NULL, ".", &saveptr))) {
1552 err = btf_find_member(btf, base_type, 0, name, &member_tid, &member_offset);
1554 fprintf(stderr, "Could not find member %s for variable %s\n", name, var);
1558 sinfo->offset += member_offset / 8;
1559 sinfo->size = member_type->size;
1560 sinfo->type = member_tid;
1572 long long value = preset->ivalue;
1575 base_type = btf__type_by_id(btf, btf__resolve_type(btf, sinfo->type));
1577 fprintf(stderr, "Failed to resolve type %d\n", sinfo->type);
1578 return -EINVAL;
1582 btf__name_by_offset(btf, base_type->name_off));
1583 return -EINVAL;
1586 if (preset->type == ENUMERATOR) {
1588 if (enum_value_from_name(btf, base_type, preset->svalue, &value)) {
1590 "Failed to find integer value for enum element %s\n",
1591 preset->svalue);
1592 return -EINVAL;
1596 preset->svalue, btf__name_by_offset(btf, base_type->name_off));
1597 return -EINVAL;
1602 if (sinfo->size < sizeof(value)) {
1604 __u32 unsigned_bits = sinfo->size * 8 - (is_signed ? 1 : 0);
1607 if (value >= max_val || value < -max_val) {
1610 btf__name_by_offset(btf, base_type->name_off), value,
1611 is_signed ? -max_val : 0, max_val - 1);
1612 return -EINVAL;
1617 if (!ptr || sinfo->offset + sinfo->size > size)
1618 return -EINVAL;
1621 memcpy(ptr + sinfo->offset, &value, sinfo->size);
1623 __u8 src_offset = sizeof(value) - sinfo->size;
1625 memcpy(ptr + sinfo->offset, (void *)&value + src_offset, sinfo->size);
1637 int i, j, k, n, cnt, err = 0;
1644 return -EINVAL;
1646 cnt = btf__type_cnt(btf);
1647 for (i = 1; i != cnt; ++i) {
1654 sec_name = btf__name_by_offset(btf, t->name_off);
1661 const struct btf_type *var_type = btf__type_by_id(btf, sinfo->type);
1668 var_name = btf__name_by_offset(btf, var_type->name_off);
1674 if (strncmp(var_name, presets[k].name, var_len) != 0 ||
1675 (presets[k].name[var_len] != '\0' &&
1676 presets[k].name[var_len] != '.'))
1682 return -EINVAL;
1686 &tmp_sinfo, presets[k].name);
1701 presets[i].name);
1742 fprintf(stderr, "Failed to open '%s': %d\n", filename, -errno);
1771 err = -errno;
1805 enum stat_id id, bool asc, bool abs)
1811 cmp = strcmp(s1->file_name, s2->file_name);
1814 cmp = strcmp(s1->prog_name, s2->prog_name);
1828 long v1 = s1->stats[id];
1829 long v2 = s2->stats[id];
1832 v1 = v1 < 0 ? -v1 : v1;
1833 v2 = v2 < 0 ? -v2 : v2;
1837 cmp = v1 < v2 ? -1 : 1;
1845 return asc ? cmp : -cmp;
1861 cmp = strcmp(s1->file_name, s2->file_name);
1864 return strcmp(s1->prog_name, s2->prog_name);
1868 enum stat_id id, enum stat_variant var,
1875 *str_val = s->file_name;
1879 *str_val = s->prog_name;
1883 v1 = s->stats_a ? s->stats_a->stats[id] : 0;
1884 v2 = s->stats_b ? s->stats_b->stats[id] : 0;
1888 if (!s->stats_a)
1889 *num_val = -DBL_MAX;
1891 *num_val = s->stats_a->stats[id];
1894 if (!s->stats_b)
1895 *num_val = -DBL_MAX;
1897 *num_val = s->stats_b->stats[id];
1900 if (!s->stats_a || !s->stats_b)
1901 *num_val = -DBL_MAX;
1905 *num_val = (double)(v2 - v1);
1908 if (!s->stats_a || !s->stats_b) {
1909 *num_val = -DBL_MAX;
1914 *num_val = v2 < v1 ? -100.0 : 100.0;
1916 *num_val = (v2 - v1) * 100.0 / v1;
1924 enum stat_id id, enum stat_variant var,
1942 cmp = v1 < v2 ? -1 : 1;
1944 return asc ? cmp : -cmp;
1963 cmp = strcmp(s1->file_name, s2->file_name);
1966 return strcmp(s1->prog_name, s2->prog_name);
1969 #define HEADER_CHAR '-'
1986 static void output_headers(enum resfmt fmt)
2002 fmt_str = stat_defs[id].left_aligned ? "%s%-*s" : "%s%*s";
2004 if (i == env.output_spec.spec_cnt - 1)
2009 if (i == env.output_spec.spec_cnt - 1)
2019 static void prepare_value(const struct verif_stats *s, enum stat_id id,
2024 *str = s ? s->file_name : "N/A";
2027 *str = s ? s->prog_name : "N/A";
2033 *str = s->stats[VERDICT] ? "success" : "failure";
2039 *str = libbpf_bpf_attach_type_str(s->stats[ATTACH_TYPE]) ?: "N/A";
2045 *str = libbpf_bpf_prog_type_str(s->stats[PROG_TYPE]) ?: "N/A";
2056 *val = s ? s->stats[id] : 0;
2064 static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last)
2087 printf("%s%-*s", i == 0 ? "" : COLUMN_SEP, *max_len, str);
2090 if (i == env.output_spec.spec_cnt - 1)
2098 if (i == env.output_spec.spec_cnt - 1)
2111 static int parse_stat_value(const char *str, enum stat_id id, struct verif_stats *st)
2115 st->file_name = strdup(str);
2116 if (!st->file_name)
2117 return -ENOMEM;
2120 st->prog_name = strdup(str);
2121 if (!st->prog_name)
2122 return -ENOMEM;
2126 st->stats[VERDICT] = true;
2128 st->stats[VERDICT] = false;
2131 return -EINVAL;
2147 err = -errno;
2152 st->stats[id] = val;
2156 enum bpf_prog_type prog_type = 0;
2161 st->stats[id] = prog_type;
2169 return -EINVAL;
2174 enum bpf_attach_type attach_type = 0;
2179 st->stats[id] = attach_type;
2187 return -EINVAL;
2193 return -EINVAL;
2208 err = -errno;
2218 int col = 0, cnt = 0;
2225 err = -ENOMEM;
2236 while ((next = strtok_r(cnt++ ? NULL : input, ",\n", &state))) {
2246 if (col >= specs->spec_cnt) {
2249 err = -EINVAL;
2252 err = parse_stat_value(next, specs->ids[col], st);
2263 if (col < specs->spec_cnt) {
2266 err = -EINVAL;
2270 if (!st->file_name || !st->prog_name) {
2271 fprintf(stderr, "Row #%d in '%s' is missing file and/or program name\n",
2273 err = -EINVAL;
2281 if (!should_process_file_prog(st->file_name, st->prog_name)) {
2282 free(st->file_name);
2283 free(st->prog_name);
2284 *stat_cntp -= 1;
2289 err = -errno;
2301 static bool is_key_stat(enum stat_id id)
2326 static void output_comp_headers(enum resfmt fmt)
2339 bool last = (i == env.output_spec.spec_cnt - 1) && (j == max_j - 1);
2351 printf("%s%-*s%s", i + j == 0 ? "" : COLUMN_SEP,
2352 *max_len - (int)strlen(sfx), stat_defs[id].header, sfx);
2371 enum resfmt fmt, bool last)
2373 const struct verif_stats *base = join_stats->stats_a;
2374 const struct verif_stats *comp = join_stats->stats_b;
2391 /* key stats (file and program name) are always strings */
2417 diff_val = comp_val - base_val;
2425 p = comp_val < base_val ? -100.0 : 100.0;
2448 /* string outputs are left-aligned, number outputs are right-aligned */
2449 const char *fmt = base_str ? "%s%-*s" : "%s%*s";
2456 if (i == env.output_spec.spec_cnt - 1)
2466 if (i == env.output_spec.spec_cnt - 1)
2480 r = strcmp(base->file_name, comp->file_name);
2483 return strcmp(base->prog_name, comp->prog_name);
2488 static const double eps = 1e-9;
2492 fetch_join_stat_value(stats, f->stat_id, f->stat_var, &str, &value);
2494 if (f->abs)
2497 switch (f->op) {
2498 case OP_EQ: return value > f->value - eps && value < f->value + eps;
2499 case OP_NEQ: return value < f->value - eps || value > f->value + eps;
2500 case OP_LT: return value < f->value - eps;
2501 case OP_LE: return value <= f->value + eps;
2502 case OP_GT: return value > f->value + eps;
2503 case OP_GE: return value >= f->value - eps;
2506 fprintf(stderr, "BUG: unknown filter op %d!\n", f->op);
2517 if (f->kind != FILTER_STAT)
2526 if (f->kind != FILTER_STAT)
2542 enum resfmt cur_fmt;
2543 int err, i, j, last_idx, cnt;
2548 return -EINVAL;
2566 * pre-processing later.
2572 return -EINVAL;
2580 return -EINVAL;
2584 /* Replace user-specified sorting spec with file+prog sorting rule to
2609 if (!base->file_name || !base->prog_name) {
2610 fprintf(stderr, "Entry #%d in '%s' doesn't have file and/or program name specified!\n",
2612 return -EINVAL;
2614 if (!comp->file_name || !comp->prog_name) {
2615 fprintf(stderr, "Entry #%d in '%s' doesn't have file and/or program name specified!\n",
2617 return -EINVAL;
2622 return -ENOMEM;
2630 join->file_name = base->file_name;
2631 join->prog_name = base->prog_name;
2632 join->stats_a = base;
2633 join->stats_b = comp;
2637 join->file_name = base->file_name;
2638 join->prog_name = base->prog_name;
2639 join->stats_a = base;
2640 join->stats_b = NULL;
2643 join->file_name = comp->file_name;
2644 join->prog_name = comp->prog_name;
2645 join->stats_a = NULL;
2646 join->stats_b = comp;
2651 return -EINVAL;
2659 /* for human-readable table output we need to do extra pass to
2672 last_idx = -1;
2673 cnt = 0;
2680 if (env.top_n && cnt >= env.top_n)
2688 cnt++;
2701 long value = stats->stats[f->stat_id];
2703 if (f->abs)
2704 value = value < 0 ? -value : value;
2706 switch (f->op) {
2707 case OP_EQ: return value == f->value;
2708 case OP_NEQ: return value != f->value;
2709 case OP_LT: return value < f->value;
2710 case OP_LE: return value <= f->value;
2711 case OP_GT: return value > f->value;
2712 case OP_GE: return value >= f->value;
2715 fprintf(stderr, "BUG: unknown filter op %d!\n", f->op);
2726 if (f->kind != FILTER_STAT)
2735 if (f->kind != FILTER_STAT)
2750 int i, last_stat_idx = 0, cnt = 0;
2770 if (env.top_n && cnt >= env.top_n)
2773 cnt++;
2784 return -EINVAL;
2810 return -EINVAL;
2888 free(env.presets[i].name);
2893 return -err;