From patchwork Wed Oct 20 01:31:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalesh Singh X-Patchwork-Id: 12571481 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8E2ADC433FE for ; Wed, 20 Oct 2021 01:33:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6C506610CC for ; Wed, 20 Oct 2021 01:33:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229735AbhJTBgI (ORCPT ); Tue, 19 Oct 2021 21:36:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46296 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229603AbhJTBgI (ORCPT ); Tue, 19 Oct 2021 21:36:08 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 94243C061746 for ; Tue, 19 Oct 2021 18:33:54 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id v70-20020a256149000000b005ba4d61ea0fso27941138ybb.22 for ; Tue, 19 Oct 2021 18:33:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:cc; bh=KnOr7VusvEl2nOBWpkm4SdPaotgSdz121uuu2iozEYg=; b=f1+R/8BH6N9Ykke7x90tzzZZZ8+VSZ/GM8LQg7CwgILrCr8q0G8vwYrNAuasCMowbD rrDO+5wYSRhnm658/7ubdw9KldX27XDi9HQO8nHLcEvy0X+Qyw9uZhTEQoPXSmIH6jKa CprT61BHVH5h4gd4uCJuFx8HAm4P/S/rUv0mYAcLaPxrnD0TXdw8T06+rZEeZehyAYNV xh1eRGDn2wJP3yc1kxm3iqKsvBgIL+FRtc3/3WL43nHQP9qRmoKOZNMZ2Lb3do/Pxzgp XLShggZ0n+1ItEn1AyB/wrWgDAOFBS/r3UpVE6+FTydWoXyiiFw7bQ4VlJQ95BPnn6rL 5D9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:cc; bh=KnOr7VusvEl2nOBWpkm4SdPaotgSdz121uuu2iozEYg=; b=REDEiqsPDvtLlH3QBxfJ2aOZJ+cohtGL/ix5+ufE1IikqThm4N0Vm5gxG0lzJ9jRBQ LQ1uxyN2hPKShNpYRWFeP0OmRd7koLtVspOqVFuFXdWLRjf6/E58mWURqE/1LTPxguqA 7PCoRVy7Gu7sxwk5w3szBc6x1kHCltiTNHtuQOmeVYwzxip33VuKzB6mJGQZO0I7yHPU 4GV2AfDc0mwqkpBK7hUGn+YfIMM+tbjBbO5telUQwhv27JIp9+6ECYYBwSVynnPTDz1d /aS6/+xpl7MOMoT6NBgNm32JNtL1EGi7wg27/TfaqQZ8BRPpprWUPFN4CasEXbJjcaLm m+Ng== X-Gm-Message-State: AOAM530lNOoAW9Pkq9/ldyr1oP+JrOCm3gY1Yhrsp8n438mfZvsTv6xe aWXtAybEu04AXAh8N0Xn9mQLW5JhaPvQyQp4Xw== X-Google-Smtp-Source: ABdhPJysUEJoXQgDrKhMj3mtsNH7cL8sAUGkKm4g3PPrOWZ5oIfuXlpIQHH90rl/VRrZCQUNqW7qNzwK6UIZFA0I4w== X-Received: from kaleshsingh.mtv.corp.google.com ([2620:15c:211:200:1953:b886:7a6c:bf0]) (user=kaleshsingh job=sendgmr) by 2002:a25:ac11:: with SMTP id w17mr43291157ybi.282.1634693633829; Tue, 19 Oct 2021 18:33:53 -0700 (PDT) Date: Tue, 19 Oct 2021 18:31:38 -0700 In-Reply-To: <20211020013153.4106001-1-kaleshsingh@google.com> Message-Id: <20211020013153.4106001-2-kaleshsingh@google.com> Mime-Version: 1.0 References: <20211020013153.4106001-1-kaleshsingh@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH v2 1/5] tracing: Add support for creating hist trigger variables from literal From: Kalesh Singh Cc: surenb@google.com, hridya@google.com, namhyung@kernel.org, kernel-team@android.com, Kalesh Singh , Jonathan Corbet , Steven Rostedt , Ingo Molnar , Shuah Khan , Masami Hiramatsu , Tom Zanussi , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Currently hist trigger expressions don't support the use of numeric literals: e.g. echo 'hist:keys=common_pid:x=$y-1234' --> is not valid expression syntax Having the ability to use numeric constants in hist triggers supports a wider range of expressions for creating variables. Add support for creating trace event histogram variables from numeric literals. e.g. echo 'hist:keys=common_pid:x=1234,y=size-1024' >> event/trigger A negative numeric constant is created, using unary minus operator (parentheses are required). e.g. echo 'hist:keys=common_pid:z=-(2)' >> event/trigger Constants can be used with division/multiplication (added in the next patch in this series) to implement granularity filters for frequent trace events. For instance we can limit emitting the rss_stat trace event to when there is a 512KB cross over in the rss size: # Create a synthetic event to monitor instead of the high frequency # rss_stat event echo 'rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size' >> tracing/synthetic_events # Create a hist trigger that emits the synthetic rss_stat_throttled # event only when the rss size crosses a 512KB boundary. echo 'hist:keys=keys=mm_id,member:bucket=size/0x80000:onchange($bucket) .rss_stat_throttled(mm_id,curr,member,size)' >> events/kmem/rss_stat/trigger A use case for using constants with addition/subtraction is not yet known, but for completeness the use of constants are supported for all operators. Signed-off-by: Kalesh Singh Reviewed-by: Namhyung Kim --- Changes in v2: - Add description of use case for constants in arithmetic operations, per Steven Rostedt - Add Namhyung's Reviewed-by kernel/trace/trace_events_hist.c | 80 +++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index f01e442716e2..8563a2d51f65 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -66,7 +66,9 @@ C(EMPTY_SORT_FIELD, "Empty sort field"), \ C(TOO_MANY_SORT_FIELDS, "Too many sort fields (Max = 2)"), \ C(INVALID_SORT_FIELD, "Sort field must be a key or a val"), \ - C(INVALID_STR_OPERAND, "String type can not be an operand in expression"), + C(INVALID_STR_OPERAND, "String type can not be an operand in expression"), \ + C(TOO_MANY_CONSTS, "Too many constants defined"), \ + C(EXPECT_NUMBER, "Expecting numeric literal"), #undef C #define C(a, b) HIST_ERR_##a @@ -89,6 +91,8 @@ typedef u64 (*hist_field_fn_t) (struct hist_field *field, #define HIST_FIELD_OPERANDS_MAX 2 #define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX) #define HIST_ACTIONS_MAX 8 +#define HIST_CONST_MAX 4 +#define HIST_CONST_DIGITS_MAX 21 enum field_op_id { FIELD_OP_NONE, @@ -152,6 +156,9 @@ struct hist_field { bool read_once; unsigned int var_str_idx; + + /* Numeric literals are represented as u64 */ + u64 constant; }; static u64 hist_field_none(struct hist_field *field, @@ -163,6 +170,15 @@ static u64 hist_field_none(struct hist_field *field, return 0; } +static u64 hist_field_const(struct hist_field *field, + struct tracing_map_elt *elt, + struct trace_buffer *buffer, + struct ring_buffer_event *rbe, + void *event) +{ + return field->constant; +} + static u64 hist_field_counter(struct hist_field *field, struct tracing_map_elt *elt, struct trace_buffer *buffer, @@ -341,6 +357,7 @@ enum hist_field_flags { HIST_FIELD_FL_CPU = 1 << 15, HIST_FIELD_FL_ALIAS = 1 << 16, HIST_FIELD_FL_BUCKET = 1 << 17, + HIST_FIELD_FL_CONST = 1 << 18, }; struct var_defs { @@ -410,6 +427,7 @@ struct hist_trigger_data { struct field_var *save_vars[SYNTH_FIELDS_MAX]; unsigned int n_save_vars; unsigned int n_save_var_str; + unsigned int n_constants; }; struct action_data; @@ -1516,6 +1534,12 @@ static void expr_field_str(struct hist_field *field, char *expr) { if (field->flags & HIST_FIELD_FL_VAR_REF) strcat(expr, "$"); + else if (field->flags & HIST_FIELD_FL_CONST) { + char str[HIST_CONST_DIGITS_MAX]; + + snprintf(str, HIST_CONST_DIGITS_MAX, "%llu", field->constant); + strcat(expr, str); + } strcat(expr, hist_field_name(field, 0)); @@ -1689,6 +1713,15 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data, goto out; } + if (flags & HIST_FIELD_FL_CONST) { + hist_field->fn = hist_field_const; + hist_field->size = sizeof(u64); + hist_field->type = kstrdup("u64", GFP_KERNEL); + if (!hist_field->type) + goto free; + goto out; + } + if (flags & HIST_FIELD_FL_STACKTRACE) { hist_field->fn = hist_field_none; goto out; @@ -2090,6 +2123,35 @@ static struct hist_field *create_alias(struct hist_trigger_data *hist_data, return alias; } +static struct hist_field *parse_const(struct hist_trigger_data *hist_data, + char *str, char *var_name, + unsigned long *flags) +{ + struct trace_array *tr = hist_data->event_file->tr; + struct hist_field *field = NULL; + u64 constant; + + if (hist_data->n_constants >= HIST_CONST_MAX) { + hist_err(tr, HIST_ERR_TOO_MANY_CONSTS, errpos(str)); + return NULL; + } + + if (kstrtoull(str, 0, &constant)) { + hist_err(tr, HIST_ERR_EXPECT_NUMBER, errpos(str)); + return NULL; + } + + *flags |= HIST_FIELD_FL_CONST; + field = create_hist_field(hist_data, NULL, *flags, var_name); + if (!field) + return NULL; + + field->constant = constant; + hist_data->n_constants++; + + return field; +} + static struct hist_field *parse_atom(struct hist_trigger_data *hist_data, struct trace_event_file *file, char *str, unsigned long *flags, char *var_name) @@ -2100,6 +2162,15 @@ static struct hist_field *parse_atom(struct hist_trigger_data *hist_data, unsigned long buckets = 0; int ret = 0; + if (isdigit(str[0])) { + hist_field = parse_const(hist_data, str, var_name, flags); + if (!hist_field) { + ret = -EINVAL; + goto out; + } + return hist_field; + } + s = strchr(str, '.'); if (s) { s = strchr(++s, '.'); @@ -4950,6 +5021,8 @@ static void hist_field_debug_show_flags(struct seq_file *m, if (flags & HIST_FIELD_FL_ALIAS) seq_puts(m, " HIST_FIELD_FL_ALIAS\n"); + else if (flags & HIST_FIELD_FL_CONST) + seq_puts(m, " HIST_FIELD_FL_CONST\n"); } static int hist_field_debug_show(struct seq_file *m, @@ -4971,6 +5044,9 @@ static int hist_field_debug_show(struct seq_file *m, field->var.idx); } + if (field->flags & HIST_FIELD_FL_CONST) + seq_printf(m, " constant: %llu\n", field->constant); + if (field->flags & HIST_FIELD_FL_ALIAS) seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n", field->var_ref_idx); @@ -5213,6 +5289,8 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field) if (hist_field->flags & HIST_FIELD_FL_CPU) seq_puts(m, "common_cpu"); + else if (hist_field->flags & HIST_FIELD_FL_CONST) + seq_printf(m, "%llu", hist_field->constant); else if (field_name) { if (hist_field->flags & HIST_FIELD_FL_VAR_REF || hist_field->flags & HIST_FIELD_FL_ALIAS) From patchwork Wed Oct 20 01:31:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalesh Singh X-Patchwork-Id: 12571483 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6642FC433EF for ; Wed, 20 Oct 2021 01:34:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 484F16117A for ; Wed, 20 Oct 2021 01:34:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229555AbhJTBgY (ORCPT ); Tue, 19 Oct 2021 21:36:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229839AbhJTBgX (ORCPT ); Tue, 19 Oct 2021 21:36:23 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD2BAC061749 for ; Tue, 19 Oct 2021 18:34:09 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id y18-20020a25a092000000b005bddb39f160so26394275ybh.10 for ; Tue, 19 Oct 2021 18:34:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:cc; bh=QoyL/j4Wj5xtQouIJDIdg2CMTweye3z9i1beCqJqXYs=; b=Zw3jTItRnv/CJli7JslBJen12pbdK99RkpUXc0nkc0zUSAySAtJbYkRKEI8joNJr59 cBZqPCZX3zMuHXTJADhzSz/ru2z+OsZoqvnKok1CLc27jw0jAWWi8zDpMz3O5b/wDU5f UwFb1/Iqj0Foq0RC2L4ntvG+WBje7P2yca6VG/6tl4FHPyxxpeuYKGSr0/+x8dDagRPP nKl2dh/WItLL0Brnetrw3YCGNd6lueLntINApGPWW+iUK+sfkbXgNfeZKhNjBFtQwSfx r3gCve22ppGU0Z99Eh+UYIqYCAWgXOiL1K3dsSOi3Pxsk77v2jBb/U9jQrLwTuAsYaMw x7Tw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:cc; bh=QoyL/j4Wj5xtQouIJDIdg2CMTweye3z9i1beCqJqXYs=; b=NBm+aCPo1lxJyKTqprm22Bc0kreHYH9OOIgsQF6AaX1nSehD4ssJdgaaQgXY+Qdsk8 nDLh6hP9xHd11TqZDXyePTgA55OsMm7DJlX87XdauQ4s7sSPhbnqCvKYIfnbs74aDKGX nycb8X9ThxM2pxF1Jm/s0kyXOzWCES7oFWg1JCxf58/m1EuehAlyIdm3MLSJiJEynCh2 cmWXjekgUQ1VtMwcfBiCxbOaBj0DPAHeAzPKaRAoivmjWdSRsuKW2b7zMURc1mzGqqYc XaOLokitLuNUGlkun8aoh4siVIN6sWSF/iwL1GxAs7RQztiYoQNDk26GkznP+f8v64AT 8Rbg== X-Gm-Message-State: AOAM5302gJbQFmha0wsGTZCo00W8BYvEOSFtYa1PDa5enAqBrp0rgVz8 Zvbb2DYzGcYtUVpREiKBZ+fCm6Uss31sAL5dog== X-Google-Smtp-Source: ABdhPJyDLS9Bp3kyfvBbh/WllX3HyAO9JB+5Aw4IPjnhXh1jJvgcTD9BGo3pTTYMLjQzjXA1Fssg+oNmS6BG+vmtWg== X-Received: from kaleshsingh.mtv.corp.google.com ([2620:15c:211:200:1953:b886:7a6c:bf0]) (user=kaleshsingh job=sendgmr) by 2002:a25:c696:: with SMTP id k144mr37146969ybf.296.1634693649086; Tue, 19 Oct 2021 18:34:09 -0700 (PDT) Date: Tue, 19 Oct 2021 18:31:39 -0700 In-Reply-To: <20211020013153.4106001-1-kaleshsingh@google.com> Message-Id: <20211020013153.4106001-3-kaleshsingh@google.com> Mime-Version: 1.0 References: <20211020013153.4106001-1-kaleshsingh@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH v2 2/5] tracing: Add division and multiplication support for hist triggers From: Kalesh Singh Cc: surenb@google.com, hridya@google.com, namhyung@kernel.org, kernel-team@android.com, Kalesh Singh , Jonathan Corbet , Steven Rostedt , Ingo Molnar , Shuah Khan , Masami Hiramatsu , Tom Zanussi , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Adds basic support for division and multiplication operations for hist trigger variable expressions. For simplicity this patch only supports, division and multiplication for a single operation expression (e.g. x=$a/$b), as currently expressions are always evaluated right to left. This can lead to some incorrect results: e.g. echo 'hist:keys=common_pid:x=8-4-2' >> event/trigger 8-4-2 should evaluate to 2 i.e. (8-4)-2 but currently x evaluate to 6 i.e. 8-(4-2) Multiplication and division in sub-expressions will work correctly, once correct operator precedence support is added (See next patch in this series). For the undefined case of division by 0, the histogram expression evaluates to (u64)(-1). Since this cannot be detected when the expression is created, it is the responsibility of the user to be aware and account for this possibility. Examples: echo 'hist:keys=common_pid:a=8,b=4,x=$a/$b' \ >> event/trigger echo 'hist:keys=common_pid:y=5*$b' \ >> event/trigger Signed-off-by: Kalesh Singh --- Changes in v2: - Use div64 helper in hist_field_div() to avoid faults on x86 32-bit machines, per Steven Rostedt kernel/trace/trace_events_hist.c | 72 +++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 8563a2d51f65..9415ee65acc0 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -99,6 +99,8 @@ enum field_op_id { FIELD_OP_PLUS, FIELD_OP_MINUS, FIELD_OP_UNARY_MINUS, + FIELD_OP_DIV, + FIELD_OP_MULT, }; /* @@ -287,6 +289,40 @@ static u64 hist_field_minus(struct hist_field *hist_field, return val1 - val2; } +static u64 hist_field_div(struct hist_field *hist_field, + struct tracing_map_elt *elt, + struct trace_buffer *buffer, + struct ring_buffer_event *rbe, + void *event) +{ + struct hist_field *operand1 = hist_field->operands[0]; + struct hist_field *operand2 = hist_field->operands[1]; + + u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event); + u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event); + + /* Return -1 for the undefined case */ + if (!val2) + return -1; + + return div64_u64(val1, val2); +} + +static u64 hist_field_mult(struct hist_field *hist_field, + struct tracing_map_elt *elt, + struct trace_buffer *buffer, + struct ring_buffer_event *rbe, + void *event) +{ + struct hist_field *operand1 = hist_field->operands[0]; + struct hist_field *operand2 = hist_field->operands[1]; + + u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event); + u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event); + + return val1 * val2; +} + static u64 hist_field_unary_minus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct trace_buffer *buffer, @@ -1595,6 +1631,12 @@ static char *expr_str(struct hist_field *field, unsigned int level) case FIELD_OP_PLUS: strcat(expr, "+"); break; + case FIELD_OP_DIV: + strcat(expr, "/"); + break; + case FIELD_OP_MULT: + strcat(expr, "*"); + break; default: kfree(expr); return NULL; @@ -1610,7 +1652,7 @@ static int contains_operator(char *str) enum field_op_id field_op = FIELD_OP_NONE; char *op; - op = strpbrk(str, "+-"); + op = strpbrk(str, "+-/*"); if (!op) return FIELD_OP_NONE; @@ -1631,6 +1673,12 @@ static int contains_operator(char *str) case '+': field_op = FIELD_OP_PLUS; break; + case '/': + field_op = FIELD_OP_DIV; + break; + case '*': + field_op = FIELD_OP_MULT; + break; default: break; } @@ -2370,10 +2418,26 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, case FIELD_OP_PLUS: sep = "+"; break; + case FIELD_OP_DIV: + sep = "/"; + break; + case FIELD_OP_MULT: + sep = "*"; + break; default: goto free; } + /* + * Multiplication and division are only supported in single operator + * expressions, since the expression is always evaluated from right + * to left. + */ + if ((field_op == FIELD_OP_DIV || field_op == FIELD_OP_MULT) && level > 0) { + hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str)); + return ERR_PTR(-EINVAL); + } + operand1_str = strsep(&str, sep); if (!operand1_str || !str) goto free; @@ -2445,6 +2509,12 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, case FIELD_OP_PLUS: expr->fn = hist_field_plus; break; + case FIELD_OP_DIV: + expr->fn = hist_field_div; + break; + case FIELD_OP_MULT: + expr->fn = hist_field_mult; + break; default: ret = -EINVAL; goto free; From patchwork Wed Oct 20 01:31:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalesh Singh X-Patchwork-Id: 12571485 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1E9EDC433F5 for ; Wed, 20 Oct 2021 01:34:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 063006117A for ; Wed, 20 Oct 2021 01:34:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229789AbhJTBgj (ORCPT ); Tue, 19 Oct 2021 21:36:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46444 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229822AbhJTBgj (ORCPT ); Tue, 19 Oct 2021 21:36:39 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AC277C061749 for ; Tue, 19 Oct 2021 18:34:25 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id u84-20020a254757000000b005bbc2bc51fcso21300297yba.3 for ; Tue, 19 Oct 2021 18:34:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:cc; bh=E6LsuPT3sCsEi4Zp/VZ8W05eFESmOHRwQobyJf9PDAU=; b=e8PT+xyX2VIPOarEAwk7dRqrwAq1/cpTrEVbKAgKNBLqiVxbO9a3i6g6pokseFQtYO 8Nlq0ZHaAtxMKWNI0R/MuBvh4M0SZH+YWcsXWzanOB4i9iRlawcmK8wV50Y4cvOiNQDw 3hqLHxTk6tpMYduyNjcvYbo51t/Duog9ISfn9dFZTg4V9ZyL6hfXvep+2l4TqN6SJhbG CdF34x8C+AUw+pJKdSYvXOX1EmPtVRKtX1WHuj884NjmD5CY/buHhBtJ3efDQBlL6U6p 8AR/LyQZxd9DpmPFr/GcwPPuFRUQge8mmcWyo68DB55kSEthEB6HHHgsKMD4e/0i0ip6 3PCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:cc; bh=E6LsuPT3sCsEi4Zp/VZ8W05eFESmOHRwQobyJf9PDAU=; b=G+/t33WrlKSqSw1HU3gEFpCiS8j9R/00cz9HbpamdbevBexai3sk2ptVCwudRD1FAP ugTO9f2uX7p0Nif0fnncMevyQdVazeHfjQMPdB9MWHa97KyHWd20ZoRBCFREOZjM33ZN yN2kUgPjCcPEfqRWJlm5gxVilqn8T5/A2MNHucDYQpmocuezHBcGEplA/tSJeUzezq56 IjF/bWoM7HNvHmT1wRpGyhJBzo34tCH1NL7h2bF9eij5eQvdfAOnOdWI0ed4EIQwXfBf Mnd4sANY2Z96RW/5OkLlrOXakarQhgIXgPfeWvt84TC/9llexgfZwlguT7t+r2eetfDx UX0w== X-Gm-Message-State: AOAM530l40lIQAlH6GCq1KJbpwYX5I7bJPwsuSv0Dnff52cVMMjDHhjg kubTfTFqB7lDS9A+0lSsOOg7GDJnVRbEVWtByQ== X-Google-Smtp-Source: ABdhPJxQ0lEpI+LfcyC7prj9h7MYOPG0MyNVoH7NnHyKZHmfq7e0TvJ9uggtBs+3S6gsqEsNHdci+QFJ4rE9xquZig== X-Received: from kaleshsingh.mtv.corp.google.com ([2620:15c:211:200:1953:b886:7a6c:bf0]) (user=kaleshsingh job=sendgmr) by 2002:a25:8287:: with SMTP id r7mr41211463ybk.365.1634693664882; Tue, 19 Oct 2021 18:34:24 -0700 (PDT) Date: Tue, 19 Oct 2021 18:31:40 -0700 In-Reply-To: <20211020013153.4106001-1-kaleshsingh@google.com> Message-Id: <20211020013153.4106001-4-kaleshsingh@google.com> Mime-Version: 1.0 References: <20211020013153.4106001-1-kaleshsingh@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH v2 3/5] tracing: Fix operator precedence for hist triggers expression From: Kalesh Singh Cc: surenb@google.com, hridya@google.com, namhyung@kernel.org, kernel-team@android.com, Kalesh Singh , Jonathan Corbet , Steven Rostedt , Ingo Molnar , Shuah Khan , Masami Hiramatsu , Tom Zanussi , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org The current histogram expression evaluation logic evaluates the expression from right to left. This can lead to incorrect results if the operations are not associative (as is the case for subtraction and, the now added, division operators). e.g. 16-8-4-2 should be 2 not 10 --> 16-8-4-2 = ((16-8)-4)-2 64/8/4/2 should be 1 not 16 --> 64/8/4/2 = ((64/8)/4)/2 Division and multiplication are currently limited to single operation expression due to operator precedence support not yet implemented. Rework the expression parsing to support the correct evaluation of expressions containing operators of different precedences; and fix the associativity error by evaluating expressions with operators of the same precedence from left to right. Examples: (1) echo 'hist:keys=common_pid:a=8,b=4,c=2,d=1,w=$a-$b-$c-$d' \ >> event/trigger (2) echo 'hist:keys=common_pid:x=$a/$b/3/2' >> event/trigger (3) echo 'hist:keys=common_pid:y=$a+10/$c*1024' >> event/trigger (4) echo 'hist:keys=common_pid:z=$a/$b+$c*$d' >> event/trigger Signed-off-by: Kalesh Singh Reviewed-by: Namhyung Kim --- Changed in v2: - Add Namhyung's Reviewed-by kernel/trace/trace_events_hist.c | 210 ++++++++++++++++++++----------- 1 file changed, 140 insertions(+), 70 deletions(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 9415ee65acc0..9205cfe120e8 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -68,7 +68,9 @@ C(INVALID_SORT_FIELD, "Sort field must be a key or a val"), \ C(INVALID_STR_OPERAND, "String type can not be an operand in expression"), \ C(TOO_MANY_CONSTS, "Too many constants defined"), \ - C(EXPECT_NUMBER, "Expecting numeric literal"), + C(EXPECT_NUMBER, "Expecting numeric literal"), \ + C(UNARY_MINUS_SUBEXPR, "Unary minus not supported in sub-expressions"), \ + C(SYM_OFFSET_SUBEXPR, ".sym-offset not supported in sub-expressions"), #undef C #define C(a, b) HIST_ERR_##a @@ -1647,40 +1649,96 @@ static char *expr_str(struct hist_field *field, unsigned int level) return expr; } -static int contains_operator(char *str) +/* + * If field_op != FIELD_OP_NONE, *sep points to the root operator + * of the expression tree to be evaluated. + */ +static int contains_operator(char *str, char **sep) { enum field_op_id field_op = FIELD_OP_NONE; - char *op; + char *minus_op, *plus_op, *div_op, *mult_op; + + + /* + * Report the last occurrence of the operators first, so that the + * expression is evaluated left to right. This is important since + * subtraction and division are not associative. + * + * e.g + * 64/8/4/2 is 1, i.e 64/8/4/2 = ((64/8)/4)/2 + * 14-7-5-2 is 0, i.e 14-7-5-2 = ((14-7)-5)-2 + */ - op = strpbrk(str, "+-/*"); - if (!op) - return FIELD_OP_NONE; + /* + * First, find lower precedence addition and subtraction + * since the expression will be evaluated recursively. + */ + minus_op = strrchr(str, '-'); + if (minus_op) { + /* Unfortunately, the modifier ".sym-offset" can confuse things. */ + if (minus_op - str >= 4 && !strncmp(minus_op - 4, ".sym-offset", 11)) + goto out; - switch (*op) { - case '-': /* - * Unfortunately, the modifier ".sym-offset" - * can confuse things. + * Unary minus is not supported in sub-expressions. If + * present, it is always the next root operator. */ - if (op - str >= 4 && !strncmp(op - 4, ".sym-offset", 11)) - return FIELD_OP_NONE; - - if (*str == '-') + if (minus_op == str) { field_op = FIELD_OP_UNARY_MINUS; - else - field_op = FIELD_OP_MINUS; - break; - case '+': - field_op = FIELD_OP_PLUS; - break; - case '/': + goto out; + } + + field_op = FIELD_OP_MINUS; + } + + plus_op = strrchr(str, '+'); + if (plus_op || minus_op) { + /* + * For operators of the same precedence use to rightmost as the + * root, so that the expression is evaluated left to right. + */ + if (plus_op > minus_op) + field_op = FIELD_OP_PLUS; + goto out; + } + + /* + * Multiplication and division have higher precedence than addition and + * subtraction. + */ + div_op = strrchr(str, '/'); + if (div_op) field_op = FIELD_OP_DIV; - break; - case '*': + + mult_op = strrchr(str, '*'); + /* + * For operators of the same precedence use to rightmost as the + * root, so that the expression is evaluated left to right. + */ + if (mult_op > div_op) field_op = FIELD_OP_MULT; - break; - default: - break; + +out: + if (sep) { + switch (field_op) { + case FIELD_OP_UNARY_MINUS: + case FIELD_OP_MINUS: + *sep = minus_op; + break; + case FIELD_OP_PLUS: + *sep = plus_op; + break; + case FIELD_OP_DIV: + *sep = div_op; + break; + case FIELD_OP_MULT: + *sep = mult_op; + break; + case FIELD_OP_NONE: + default: + *sep = NULL; + break; + } } return field_op; @@ -2006,7 +2064,7 @@ static char *field_name_from_var(struct hist_trigger_data *hist_data, if (strcmp(var_name, name) == 0) { field = hist_data->attrs->var_defs.expr[i]; - if (contains_operator(field) || is_var_ref(field)) + if (contains_operator(field, NULL) || is_var_ref(field)) continue; return field; } @@ -2275,21 +2333,24 @@ static struct hist_field *parse_atom(struct hist_trigger_data *hist_data, static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, struct trace_event_file *file, char *str, unsigned long flags, - char *var_name, unsigned int level); + char *var_name, unsigned int *n_subexprs); static struct hist_field *parse_unary(struct hist_trigger_data *hist_data, struct trace_event_file *file, char *str, unsigned long flags, - char *var_name, unsigned int level) + char *var_name, unsigned int *n_subexprs) { struct hist_field *operand1, *expr = NULL; unsigned long operand_flags; int ret = 0; char *s; + /* Unary minus operator, increment n_subexprs */ + ++*n_subexprs; + /* we support only -(xxx) i.e. explicit parens required */ - if (level > 3) { + if (*n_subexprs > 3) { hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str)); ret = -EINVAL; goto free; @@ -2306,8 +2367,16 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data, } s = strrchr(str, ')'); - if (s) + if (s) { + /* unary minus not supported in sub-expressions */ + if (*(s+1) != '\0') { + hist_err(file->tr, HIST_ERR_UNARY_MINUS_SUBEXPR, + errpos(str)); + ret = -EINVAL; + goto free; + } *s = '\0'; + } else { ret = -EINVAL; /* no closing ')' */ goto free; @@ -2321,7 +2390,7 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data, } operand_flags = 0; - operand1 = parse_expr(hist_data, file, str, operand_flags, NULL, ++level); + operand1 = parse_expr(hist_data, file, str, operand_flags, NULL, n_subexprs); if (IS_ERR(operand1)) { ret = PTR_ERR(operand1); goto free; @@ -2391,60 +2460,61 @@ static int check_expr_operands(struct trace_array *tr, static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, struct trace_event_file *file, char *str, unsigned long flags, - char *var_name, unsigned int level) + char *var_name, unsigned int *n_subexprs) { struct hist_field *operand1 = NULL, *operand2 = NULL, *expr = NULL; unsigned long operand_flags; int field_op, ret = -EINVAL; char *sep, *operand1_str; - if (level > 3) { + if (*n_subexprs > 3) { hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str)); return ERR_PTR(-EINVAL); } - field_op = contains_operator(str); + /* + * ".sym-offset" in expressions has no effect on their evaluation, + * but can confuse operator parsing. + */ + if (*n_subexprs == 0) { + sep = strstr(str, ".sym-offset"); + if (sep) { + *sep = '\0'; + if (strpbrk(str, "+-/*") || strpbrk(sep + 11, "+-/*")) { + *sep = '.'; + hist_err(file->tr, HIST_ERR_SYM_OFFSET_SUBEXPR, + errpos(sep)); + return ERR_PTR(-EINVAL); + } + *sep = '.'; + } + } + + field_op = contains_operator(str, &sep); if (field_op == FIELD_OP_NONE) return parse_atom(hist_data, file, str, &flags, var_name); if (field_op == FIELD_OP_UNARY_MINUS) - return parse_unary(hist_data, file, str, flags, var_name, ++level); + return parse_unary(hist_data, file, str, flags, var_name, n_subexprs); - switch (field_op) { - case FIELD_OP_MINUS: - sep = "-"; - break; - case FIELD_OP_PLUS: - sep = "+"; - break; - case FIELD_OP_DIV: - sep = "/"; - break; - case FIELD_OP_MULT: - sep = "*"; - break; - default: - goto free; - } + /* Binary operator found, increment n_subexprs */ + ++*n_subexprs; - /* - * Multiplication and division are only supported in single operator - * expressions, since the expression is always evaluated from right - * to left. - */ - if ((field_op == FIELD_OP_DIV || field_op == FIELD_OP_MULT) && level > 0) { - hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str)); - return ERR_PTR(-EINVAL); - } + /* Split the expression string at the root operator */ + if (!sep) + goto free; + *sep = '\0'; + operand1_str = str; + str = sep+1; - operand1_str = strsep(&str, sep); if (!operand1_str || !str) goto free; operand_flags = 0; - operand1 = parse_atom(hist_data, file, operand1_str, - &operand_flags, NULL); + + /* LHS of string is an expression e.g. a+b in a+b+c */ + operand1 = parse_expr(hist_data, file, operand1_str, operand_flags, NULL, n_subexprs); if (IS_ERR(operand1)) { ret = PTR_ERR(operand1); operand1 = NULL; @@ -2456,9 +2526,9 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, goto free; } - /* rest of string could be another expression e.g. b+c in a+b+c */ + /* RHS of string is another expression e.g. c in a+b+c */ operand_flags = 0; - operand2 = parse_expr(hist_data, file, str, operand_flags, NULL, ++level); + operand2 = parse_expr(hist_data, file, str, operand_flags, NULL, n_subexprs); if (IS_ERR(operand2)) { ret = PTR_ERR(operand2); operand2 = NULL; @@ -3892,9 +3962,9 @@ static int __create_val_field(struct hist_trigger_data *hist_data, unsigned long flags) { struct hist_field *hist_field; - int ret = 0; + int ret = 0, n_subexprs = 0; - hist_field = parse_expr(hist_data, file, field_str, flags, var_name, 0); + hist_field = parse_expr(hist_data, file, field_str, flags, var_name, &n_subexprs); if (IS_ERR(hist_field)) { ret = PTR_ERR(hist_field); goto out; @@ -4035,7 +4105,7 @@ static int create_key_field(struct hist_trigger_data *hist_data, struct hist_field *hist_field = NULL; unsigned long flags = 0; unsigned int key_size; - int ret = 0; + int ret = 0, n_subexprs = 0; if (WARN_ON(key_idx >= HIST_FIELDS_MAX)) return -EINVAL; @@ -4048,7 +4118,7 @@ static int create_key_field(struct hist_trigger_data *hist_data, hist_field = create_hist_field(hist_data, NULL, flags, NULL); } else { hist_field = parse_expr(hist_data, file, field_str, flags, - NULL, 0); + NULL, &n_subexprs); if (IS_ERR(hist_field)) { ret = PTR_ERR(hist_field); goto out; From patchwork Wed Oct 20 01:31:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalesh Singh X-Patchwork-Id: 12571487 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8AD84C433FE for ; Wed, 20 Oct 2021 01:34:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 704536117A for ; Wed, 20 Oct 2021 01:34:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229890AbhJTBg4 (ORCPT ); Tue, 19 Oct 2021 21:36:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46514 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229888AbhJTBgz (ORCPT ); Tue, 19 Oct 2021 21:36:55 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98825C061749 for ; Tue, 19 Oct 2021 18:34:41 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id c65-20020a251c44000000b005ba81fe4944so27907105ybc.14 for ; Tue, 19 Oct 2021 18:34:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:cc; bh=qaKijHBDbg4MDDE34AX+1Hb/Rx1aDbvkQ77nEsegoWQ=; b=VpP3BTmOG0fnhKEfwY8k6rT/1onZ530niR+thm5TzCJ/3FKc7MNT0Ovlut9zeHT2q9 Qphv/40SX9s/lPEp4mslzDJ8p5nDc1GqKHzilgxAmwtlL6IKxkM5m2IEECIJHdh8SCay JHuil2cDGQdeM2qVTD/SRyl7mx4z3iVINK0nTlWHoLZpxCyJ1ChRZ9Ew6aNnFeGCweJE zXLeil2hzFbNlwdQpVdtkFhhT5oGWDgtEGqIdlEUZzAF611SJbUT8db0kmz3H8N7A5Va X3gmmx9DvVheJlO/nQcdfDNXQ0Czq7qtIof85Qt1wLDGqajh1mht+awk4wz0VxAOlfRX SUuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:cc; bh=qaKijHBDbg4MDDE34AX+1Hb/Rx1aDbvkQ77nEsegoWQ=; b=aCE0uiIFL9xb7jPbHJ8XBXhTnGYwGQoJmiMxhfCV+aNsvtqqAIWAXLfGGbmHLydNzA rS+JJUj4E43B6OKtIygYpVTY1hCkhv4+nDAhBPciI/2LdBJgvGL8fD3We2jSn0/EssD8 6V3QbNx/op30tFKIJNb6I3BpZcWuREPXOgZiDfiOOBA31kgb1MEZ4z11uUlzUA90yd2y JvCBNPO9oer/jssvJSMHWmKLRv6+ckdF+WXsZV2eUlkZMmNoA55DI8X3HAZtiwCKCF1y t/CWzeP11XvEEqAdgK9PryzE6eHbHHnHD2T4Skmjb9xMFq1sZ8XOEwGi/r081xMNhAal vrUw== X-Gm-Message-State: AOAM531euwTLc4wb6c+oZuNa1EGWLcLUvmO/WwvXm/gfd2Mqy20vG9HU aPqM+mQxn+uOhHN3ke0tBIroMrtdFh5W83Q2VQ== X-Google-Smtp-Source: ABdhPJxYPBcKJ3w/+ILnLwmNfttJXo+ix+IexGVCqGCpVl2gYD2z8hAMxXucyfpNzN6YWDg035MdjovJmo2IqxMWqw== X-Received: from kaleshsingh.mtv.corp.google.com ([2620:15c:211:200:1953:b886:7a6c:bf0]) (user=kaleshsingh job=sendgmr) by 2002:a25:217:: with SMTP id 23mr39826833ybc.205.1634693680869; Tue, 19 Oct 2021 18:34:40 -0700 (PDT) Date: Tue, 19 Oct 2021 18:31:41 -0700 In-Reply-To: <20211020013153.4106001-1-kaleshsingh@google.com> Message-Id: <20211020013153.4106001-5-kaleshsingh@google.com> Mime-Version: 1.0 References: <20211020013153.4106001-1-kaleshsingh@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH v2 4/5] tracing/selftests: Add tests for hist trigger expression parsing From: Kalesh Singh Cc: surenb@google.com, hridya@google.com, namhyung@kernel.org, kernel-team@android.com, Kalesh Singh , Jonathan Corbet , Steven Rostedt , Ingo Molnar , Shuah Khan , Masami Hiramatsu , Tom Zanussi , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Add tests for the parsing of hist trigger expressions; and to validate expression evaluation. Signed-off-by: Kalesh Singh Reviewed-by: Namhyung Kim --- Changes in v2: - Add Namhyung's Reviewed-by - Update comment to clarify err_pos in "Too many subexpressions" test .../testing/selftests/ftrace/test.d/functions | 4 +- .../trigger/trigger-hist-expressions.tc | 74 +++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-expressions.tc diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index 000fd05e84b1..1855a63559ad 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions @@ -16,13 +16,13 @@ reset_tracer() { # reset the current tracer reset_trigger_file() { # remove action triggers first - grep -H ':on[^:]*(' $@ | + grep -H ':on[^:]*(' $@ | tac | while read line; do cmd=`echo $line | cut -f2- -d: | cut -f1 -d"["` file=`echo $line | cut -f1 -d:` echo "!$cmd" >> $file done - grep -Hv ^# $@ | + grep -Hv ^# $@ | tac | while read line; do cmd=`echo $line | cut -f2- -d: | cut -f1 -d"["` file=`echo $line | cut -f1 -d:` diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-expressions.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-expressions.tc new file mode 100644 index 000000000000..45399fce3483 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-expressions.tc @@ -0,0 +1,74 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: event trigger - test histogram expression parsing +# requires: set_event events/sched/sched_process_fork/trigger events/sched/sched_process_fork/hist error_log + + +fail() { #msg + echo $1 + exit_fail +} + +get_hist_var() { #var_name hist_path + hist_output=`grep -m1 "$1: " $2` + hitcount=`echo $hist_output | awk '{ for (i=1; i<=NF; ++i) { if ($i ~ "hitcount:") print $(i+1)} }'` + var_sum=`echo $hist_output | awk '{ for (i=1; i<=NF; ++i) { if ($i ~ "'$1':") print $(i+1)} }'` + var_val=$(( var_sum / hitcount )) + echo $var_val +} + +test_hist_expr() { # test_name expression expected_val + echo "Test hist trigger expressions - $1" + + echo "hist:keys=common_pid:x=$2" > events/sched/sched_process_fork/trigger + echo 'hist:keys=common_pid:vals=$x' >> events/sched/sched_process_fork/trigger + for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done + + actual=`get_hist_var x events/sched/sched_process_fork/hist` + + if [ $actual != $3 ]; then + fail "Failed hist trigger expression evaluation: Expression: $2 Expected: $3, Actual: $actual" + fi + + reset_trigger +} + +check_error() { # test_name command-with-error-pos-by-^ + echo "Test hist trigger expressions - $1" + ftrace_errlog_check 'hist:sched:sched_process_fork' "$2" 'events/sched/sched_process_fork/trigger' + reset_trigger +} + +test_hist_expr "Variable assignment" "123" "123" + +test_hist_expr "Subtraction not associative" "16-8-4-2" "2" + +test_hist_expr "Division not associative" "64/8/4/2" "1" + +test_hist_expr "Same precedence operators (+,-) evaluated left to right" "16-8+4+2" "14" + +test_hist_expr "Same precedence operators (*,/) evaluated left to right" "4*3/2*2" "12" + +test_hist_expr "Multiplication evaluated before addition/subtraction" "4+3*2-2" "8" + +test_hist_expr "Division evaluated before addition/subtraction" "4+6/2-2" "5" + +# Division by zero returns -1 +test_hist_expr "Handles division by zero" "3/0" "-1" + +# err pos for "too many subexpressions" is dependent on where +# the last subexpression was detected. This can vary depending +# on how the expression tree was generated. +check_error "Too many subexpressions" 'hist:keys=common_pid:x=32+^10*3/20-4' +check_error "Too many subexpressions" 'hist:keys=common_pid:x=^1+2+3+4+5' + +check_error "Unary minus not supported in subexpression" 'hist:keys=common_pid:x=-(^1)+2' + +check_error "'.sym-offset' modifier not supported in subexpression" \ + 'hist:keys=common_pid:x=1+common_pid^.sym-offset' +check_error "'.sym-offset' modifier not supported in subexpression" \ + 'hist:keys=common_pid:x=common_pid^.sym-offset-2' +check_error "'.sym-offset' modifier not supported in subexpression" \ + 'hist:keys=common_pid:x=4/common_pid^.sym-offset*3' + +exit 0 From patchwork Wed Oct 20 01:31:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalesh Singh X-Patchwork-Id: 12571489 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73514C433F5 for ; Wed, 20 Oct 2021 01:35:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4FF60610A2 for ; Wed, 20 Oct 2021 01:35:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229920AbhJTBhU (ORCPT ); Tue, 19 Oct 2021 21:37:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46622 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229910AbhJTBhT (ORCPT ); Tue, 19 Oct 2021 21:37:19 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1039EC061749 for ; Tue, 19 Oct 2021 18:35:06 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id q193-20020a252aca000000b005ba63482993so28083274ybq.0 for ; Tue, 19 Oct 2021 18:35:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:cc; bh=IYOJmQ2nEaASN59pmylXXLLP+FrglnzeH7l3JWIvSSI=; b=XGXOwhu+3ly4GGQ1oRi8qz2yqWWUke3CkXEYsjduM7C/tJS6yJeHXy2j5xGYawLq2z rb1FEnzkNVoLle2OjDHjZTO+RnowokFV8JDHe5avoDhfLbEKSnFnO2Vtk6N3UDhuSxty v+KTsqzaz9kw8ZRK+XP10KKGJhyeWhJ2IF9/ZzDlXeo28BAZ57R/6WkRD0tRd7hZRUqs nqR77wQaksmIDKYEDKZcJ7Fv9+8ByKyq5+OWyZfZh+CDUSSc/qhD/H0VKYKloOMGPEB3 lcj/VdaCp+ojGLKD7HKQPGhf/g0uwhUvK74T39GjDQecSd1WGaxrgrPT/QGdZDJEHvsV 8WoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:cc; bh=IYOJmQ2nEaASN59pmylXXLLP+FrglnzeH7l3JWIvSSI=; b=1qX1hJMihO8/CNGhj8g2h4FlDLa5lvf1rRXevpvSxiKsPlBz55//EXXaWJvztqObEb I8TktuiHR8oRfuojYDF/OwItd52e6MageeM2HXnoIRRC5P2x3N5VTS7t9a3u75+0rhHG YAJYKLBNranOQjbbuP4K6Nv18zCnpcVYdQIas7bYDSYFi9G7pctuEUXCWifGkFapGlU4 oxrbdza/9OLglvhq173/kfFMglux8eeCbPIESsGpzLSap0jJZweTUGFxSUMsmXL2onUh oHM0QcL+qoKvM5pb4zv2TEhqYQzgq8lc7c/+LMAhL/4z01zUlcBSjfg9MQiAz0nl+Dl2 Kqqg== X-Gm-Message-State: AOAM530ECLjI4ssddXl/M+Iqn9irR6CvLJXoCHFfVnXF8qtse9NhZFwV rJEhwJDjAjFoawrXzZCJoQPtg2wHMOQAt9txuQ== X-Google-Smtp-Source: ABdhPJwdmdJ3rocY1RE5RBQflLKGa7RbWoXi5F/Gb1zI4tZm2gFPWWaQWmi5tTLT+iznoarcNeyZ7eNWYJDXAepx0Q== X-Received: from kaleshsingh.mtv.corp.google.com ([2620:15c:211:200:1953:b886:7a6c:bf0]) (user=kaleshsingh job=sendgmr) by 2002:a25:1b0a:: with SMTP id b10mr40405957ybb.520.1634693705344; Tue, 19 Oct 2021 18:35:05 -0700 (PDT) Date: Tue, 19 Oct 2021 18:31:42 -0700 In-Reply-To: <20211020013153.4106001-1-kaleshsingh@google.com> Message-Id: <20211020013153.4106001-6-kaleshsingh@google.com> Mime-Version: 1.0 References: <20211020013153.4106001-1-kaleshsingh@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH v2 5/5] tracing/histogram: Document expression arithmetic and constants From: Kalesh Singh Cc: surenb@google.com, hridya@google.com, namhyung@kernel.org, kernel-team@android.com, Kalesh Singh , Jonathan Corbet , Steven Rostedt , Ingo Molnar , Shuah Khan , Masami Hiramatsu , Tom Zanussi , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Histogram expressions now support division, and multiplication in addition to the already supported subtraction and addition operators. Numeric constants can also be used in a hist trigger expressions or assigned to a variable and used by refernce in an expression. Signed-off-by: Kalesh Singh Reviewed-by: Namhyung Kim --- Changes in v2: - Add Namhyung's Reviewed-by Documentation/trace/histogram.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/trace/histogram.rst b/Documentation/trace/histogram.rst index 533415644c54..e12699abaee8 100644 --- a/Documentation/trace/histogram.rst +++ b/Documentation/trace/histogram.rst @@ -1763,6 +1763,20 @@ using the same key and variable from yet another event:: # echo 'hist:key=pid:wakeupswitch_lat=$wakeup_lat+$switchtime_lat ...' >> event3/trigger +Expressions support the use of addition, subtraction, multiplication and +division operators (+-*/). + +Note that division by zero always returns -1. + +Numeric constants can also be used directly in an expression:: + + # echo 'hist:keys=next_pid:timestamp_secs=common_timestamp/1000000 ...' >> event/trigger + +or assigned to a variable and referenced in a subsequent expression:: + + # echo 'hist:keys=next_pid:us_per_sec=1000000 ...' >> event/trigger + # echo 'hist:keys=next_pid:timestamp_secs=common_timestamp/$us_per_sec ...' >> event/trigger + 2.2.2 Synthetic Events ----------------------