From nobody Mon Feb 9 14:14:23 2026 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 11A701B86E9 for ; Thu, 28 Nov 2024 13:36:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732801009; cv=none; b=LwsIVjC5VG6ge3+YSEWc0KNTELKX+SXRp4d26ZythnODz2uHKKl17fKRKONOD41crDe294jtDGt9JCZMNbi1fPsRIdEUK+L1LSy+jXKcFlatx0NAMgk/obV1yoHP5c/LfB67Pgv0YqI27tS+XZKlnR491fV1xSzs4T2L5l8Vd00= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732801009; c=relaxed/simple; bh=+LNZpBhiaOxnH+Ezhfur1Zzi2CJqROuf+YAka+RZ568=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YthqeClzcveWFpMmsbdBj+2D/+I1Z8klkgBBidCIUSAsBIDKjbBdYBACfxTTGLOj1Bg5wtC1bBPMgkL/80fett6N7UL/tBMJMlYHlMjkGREWdx2WYBQgQ84T2BSqprCAkUGk/rPtQymg/4fZNJohsBRbLLBu0zIf0uSihW2dV3U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com; spf=pass smtp.mailfrom=bytedance.com; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b=VPTI5Pyu; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bytedance.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b="VPTI5Pyu" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-21210eaa803so7289035ad.2 for ; Thu, 28 Nov 2024 05:36:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1732801007; x=1733405807; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zqQaIVC+j9LhZ/TRorXPn9tvoBLETViH2KLqmtwG9as=; b=VPTI5PyuE73XIkTENBetZEkw5CAs938qyDVUgM49iravWX08cGBA6CUYpDm2M8C6L8 5YNLb9+h0RPdR4gy9HDN77bvZIw0mPcqRrBEhkf7CsIULMdvtak55RLj0bRXg57j45Yk N9uEHqR6xR/l8S/AQgsuO0AhYJwy4ZEsFw1sVnvr6OEBORVmbWWqcXzgD8HLAsgYqUO+ QiRrtevP8u7Bq9gW1y593BRwzVaLDVABGLky/WdYvVnZcDrPyGqeKgBSq8ZwZluWXDVx iYUj36vZaRGsVwO1ve8tFpP+xnu7vA4g+BIGjUy8mC4FZX/4MoYQJdhjD4847Xeii5Un cnlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732801007; x=1733405807; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zqQaIVC+j9LhZ/TRorXPn9tvoBLETViH2KLqmtwG9as=; b=EG9WvZxAvcMPA2tGrTLYPudDNcyFXx4qaVXCH6oFnUG4TivlhA0IeZrJN5KUMeXm1y dIldUemIq3rHKu7Wu6SrYEn7MSGivOxI4icsAZXJ6aeos+uhR9c80O7ZSeplOD5Qtlj2 mRDQfr02zIX9GL8aLQQvxYZGdPkOdHbt6yuNCtabzpo79whK+4N0h6szTXv6L7czWZpq CRI3mG55rGFmvW7qJfuSJ3Qr7n+5uVxxiG5JVtdmhy2W6KHF1fytBw5mXh78O/r0rPQk grvOZxC4IDmRSbCevSDrwoFaWsRxog8ShDV+LXCBVFvKAHWoF35e7icR10kV+3rBJP4i 1ozw== X-Forwarded-Encrypted: i=1; AJvYcCVlIyIAjfPvsLT56NjAmhWDjU+fMZYFooIa6lULXSAx9HcJSoYncThwaQYZtlqaLiO6v74Qrxsjh1ddNj0=@vger.kernel.org X-Gm-Message-State: AOJu0YwHvE7RT+x0PyOmHb9yrDreR9KCk/kPl6W8trP+u7cGkvZbxXee GGw8QB1Le/+l2jlPm62AtFQVNjMdrwoHNlPQkZ6MWrWoHPxkbIB/HwS6Hn4k6bs= X-Gm-Gg: ASbGncu+T+7K66BI7ODRIeUSKgYcaicTE8xU8vD0h1TWk+VRmqEBxoTXa9SunfCYv+0 DXh60SDn3BV1py7Nn7EEnuUIYYZPf+OOVVev604yR9t+g33GfyrgW223/bnxx/JOWnOGu2TTubG yYmC9uy7zPyDQ8hiZ9qa1JqVx4nC2uUlh6Pf7SqEJgsrkMPVwPRFRLR9hChrcL0LdKvsBMBnyeF luu1l/tBKKvG+6Sgi5NWSyoKxn0I2TjHzZnEjB6V5VWqKEJMWGYcqCsew== X-Google-Smtp-Source: AGHT+IF3rwvUZnobMrf3bzrwFLm6Hr8ohxbpugrVFikYQUJ5h78RZPldvuutj+6JrOe0I8HRAp8V9Q== X-Received: by 2002:a17:903:1ce:b0:211:18bc:e74b with SMTP id d9443c01a7336-21501083ab6mr108542035ad.1.1732801007302; Thu, 28 Nov 2024 05:36:47 -0800 (PST) Received: from ubuntu20.04 ([139.177.225.230]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21521985632sm12952975ad.206.2024.11.28.05.36.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Nov 2024 05:36:46 -0800 (PST) From: Yang Jihong To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com, kan.liang@linux.intel.com, james.clark@arm.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Cc: yangjihong@bytedance.com Subject: [RFC 06/12] perf event action: Add parsing print() call expr support Date: Thu, 28 Nov 2024 21:35:47 +0800 Message-Id: <20241128133553.823722-7-yangjihong@bytedance.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20241128133553.823722-1-yangjihong@bytedance.com> References: <20241128133553.823722-1-yangjihong@bytedance.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for parsing print() function calls, the parameter format is similar to C's printf(), the first parameter is a string format, and format specifiers support %c, %d, %d, %o, %u, %x, %X, %s. Currently, it simply checks whether the number of arguments matches the number of format specifiers. Signed-off-by: Yang Jihong --- tools/perf/util/parse-action.c | 329 +++++++++++++++++++++++++++++++++ tools/perf/util/parse-action.h | 1 + tools/perf/util/parse-action.l | 9 + 3 files changed, 339 insertions(+) diff --git a/tools/perf/util/parse-action.c b/tools/perf/util/parse-action.c index 40e7c8aad7be..95c06cc071ad 100644 --- a/tools/perf/util/parse-action.c +++ b/tools/perf/util/parse-action.c @@ -10,8 +10,11 @@ * - integer * - string * - call: + * - print */ =20 +#include + #include "util/debug.h" #include "util/parse-action.h" #include "util/parse-action-flex.h" @@ -171,6 +174,12 @@ static struct evtact_expr_ops expr_const_int_ops =3D { .eval =3D expr_const_int_eval, }; =20 +static bool is_const_str_expr(struct evtact_expr *expr) +{ + return expr->id =3D=3D evtact_expr_id_encode(EVTACT_EXPR_TYPE_CONST, + EVTACT_EXPR_CONST_TYPE_STR); +} + static int expr_const_str_new(struct evtact_expr *expr, void *data, int size __maybe_unused) { @@ -233,7 +242,327 @@ static struct evtact_expr_class expr_const =3D { .set_ops =3D expr_const_set_ops, }; =20 +enum print_fmt_spec_len { + PRINT_FMT_SPEC_LEN_INT, + PRINT_FMT_SPEC_LEN_LONG, + PRINT_FMT_SPEC_LEN_LONG_LONG, +}; + +enum print_fmt_spec_type { + PRINT_FMT_SPEC_TYPE_VOID, + PRINT_FMT_SPEC_TYPE_INT, + PRINT_FMT_SPEC_TYPE_STRING, +}; + +struct print_fmt_spec { + struct list_head list; + enum print_fmt_spec_type type; + enum print_fmt_spec_len len; + char *str; +}; + +#define PRINT_OUT_BUF_DEFAULT_LEN 64 +struct print_expr_priv { + struct list_head fmt_specs; + int fmt_spec_num; + int args_num; + char *out; + int out_len; +}; + +static int print_fmt_add_spec(struct print_expr_priv *priv, char *s, + regoff_t len, enum print_fmt_spec_len spec_len, + enum print_fmt_spec_type spec_type) +{ + struct print_fmt_spec *spec; + + spec =3D malloc(sizeof(*spec)); + if (spec =3D=3D NULL) { + pr_err("call print fmt spec malloc failed\n"); + return -ENOMEM; + } + + spec->str =3D strndup(s, len); + if (spec->str =3D=3D NULL) { + pr_err("call print fmt spec strndup failed\n"); + free(spec); + return -ENOMEM; + } + + spec->len =3D spec_len; + spec->type =3D spec_type; + list_add_tail(&spec->list, &priv->fmt_specs); + return 0; +} + +static int print_fmt_spec_get_len(char *s, regoff_t len) +{ + if (len =3D=3D 1 && !strncmp(s, "l", len)) + return PRINT_FMT_SPEC_LEN_LONG; + else if (len =3D=3D 2 && !strncmp(s, "ll", len)) + return PRINT_FMT_SPEC_LEN_LONG_LONG; + + return PRINT_FMT_SPEC_LEN_INT; +} + +static int print_fmt_spec_get_type(char *s) +{ + switch (s[0]) { + case 'c': + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + return PRINT_FMT_SPEC_TYPE_INT; + case 's': + return PRINT_FMT_SPEC_TYPE_STRING; + default: + break; + } + + return PRINT_FMT_SPEC_TYPE_VOID; +} + +static int print_fmt_get_string(struct evtact_expr *expr, char **fmt) +{ + int ret, fmt_len; + struct evtact_expr *fmt_expr; + + fmt_expr =3D list_first_entry_or_null(&expr->opnds, struct evtact_expr, l= ist); + if (fmt_expr =3D=3D NULL) { + pr_err("print() requires at least one argument\n"); + return -EINVAL; + } else if (!is_const_str_expr(fmt_expr)) { + pr_err("print() first argument expected to be string\n"); + return -EINVAL; + } + + if (fmt_expr->ops->eval !=3D NULL) { + ret =3D fmt_expr->ops->eval(fmt_expr, NULL, 0, (void **)fmt, &fmt_len); + if (ret) + return ret; + } + + return 0; +} + +static void print_fmt_free_specs(struct print_expr_priv *priv) +{ + struct print_fmt_spec *spec, *tmp; + + if (priv =3D=3D NULL) + return; + + list_for_each_entry_safe(spec, tmp, &priv->fmt_specs, list) { + list_del(&spec->list); + free(spec->str); + free(spec); + } +} + +static int print_fmt_split(struct evtact_expr *expr, struct print_expr_pri= v *priv) +{ + int i, ret; + char *s, *fmt; + regex_t regex; + regmatch_t pmatch[6]; + int spec_len, spec_type; + const char *const re =3D "%(-?)([0-9]*)(\\.[0-9]+)?(ll|l)?([cdosuxX])"; + + ret =3D print_fmt_get_string(expr, &fmt); + if (ret) + return ret; + + if (regcomp(®ex, re, REG_EXTENDED)) { + pr_err("expr call print fmt regcomp failed\n"); + return -1; + } + + s =3D fmt; + for (i =3D 0;; i++) { + if (regexec(®ex, s, ARRAY_SIZE(pmatch), pmatch, 0)) + break; + + spec_len =3D print_fmt_spec_get_len(s + pmatch[4].rm_so, + pmatch[4].rm_eo - pmatch[4].rm_so); + spec_type =3D print_fmt_spec_get_type(s + pmatch[5].rm_so); + + ret =3D print_fmt_add_spec(priv, s, pmatch[0].rm_eo, spec_len, spec_type= ); + if (ret) + goto out_free_specs; + + s +=3D pmatch[0].rm_eo; + } + + if ((size_t)(s - fmt) < strlen(fmt)) { + ret =3D print_fmt_add_spec(priv, s, strlen(fmt) - (s - fmt), + PRINT_FMT_SPEC_LEN_INT, PRINT_FMT_SPEC_TYPE_VOID); + if (ret) + goto out_free_specs; + } + + priv->fmt_spec_num =3D i; + return 0; + +out_free_specs: + print_fmt_free_specs(priv); + return ret; +} + +static int print_check_args(struct evtact_expr *expr, struct print_expr_pr= iv *priv) +{ + struct evtact_expr *arg; + + priv->args_num =3D 0; + list_for_each_entry(arg, &expr->opnds, list) + priv->args_num++; + + /* do not count format string argument */ + priv->args_num--; + + if (priv->args_num !=3D priv->fmt_spec_num) { + pr_err("print() arguments number for format string mismatch: %d expected= , %d provided\n", + priv->fmt_spec_num, priv->args_num); + return -EINVAL; + } + + return 0; +} + +static int expr_call_print_new(struct evtact_expr *expr, + void *data __maybe_unused, int size __maybe_unused) +{ + int ret; + struct print_expr_priv *priv; + + priv =3D malloc(sizeof(struct print_expr_priv)); + if (priv =3D=3D NULL) + return -ENOMEM; + + priv->out =3D malloc(PRINT_OUT_BUF_DEFAULT_LEN); + if (priv->out =3D=3D NULL) { + ret =3D -ENOMEM; + goto out_free_priv; + } + priv->out_len =3D PRINT_OUT_BUF_DEFAULT_LEN; + + INIT_LIST_HEAD(&priv->fmt_specs); + ret =3D print_fmt_split(expr, priv); + if (ret) + goto out_free_out_buf; + + ret =3D print_check_args(expr, priv); + if (ret) + goto out_free_specs; + + expr->priv =3D priv; + return 0; + +out_free_specs: + print_fmt_free_specs(priv); +out_free_out_buf: + free(priv->out); + priv->out_len =3D 0; +out_free_priv: + free(priv); + return ret; +} + +static void expr_call_print_free(struct evtact_expr *expr) +{ + struct print_expr_priv *priv; + + priv =3D expr->priv; + if (priv =3D=3D NULL) + return; + + print_fmt_free_specs(expr->priv); + zfree(&priv->out); + priv->out_len =3D 0; + zfree(&expr->priv); +} + +static int expr_call_print_eval(struct evtact_expr *expr, + void *in, int in_size, + void **out __maybe_unused, int *out_size __maybe_unused) +{ + int ret, len; + char *buf_out; + int arg_val_size; + unsigned long long *arg_val; + struct evtact_expr *arg; + struct print_fmt_spec *spec; + struct print_expr_priv *priv =3D expr->priv; + +retry: + len =3D 0; + priv->out[0] =3D '\0'; + arg =3D list_first_entry(&expr->opnds, struct evtact_expr, list); + list_for_each_entry(spec, &priv->fmt_specs, list) { + if (spec->type =3D=3D PRINT_FMT_SPEC_TYPE_VOID) { + len +=3D snprintf(priv->out + len, priv->out_len - len, "%s", spec->str= ); + } else { + arg =3D list_next_entry(arg, list); + if (arg =3D=3D NULL) { + pr_err("expr call print arguments are empty\n"); + return -EINVAL; + } + + ret =3D arg->ops->eval(arg, in, in_size, (void **)&arg_val, &arg_val_si= ze); + if (ret) { + pr_err("expr call print eval argument failed %d\n", ret); + return ret; + } + + if (spec->type =3D=3D PRINT_FMT_SPEC_TYPE_STRING) { + len +=3D snprintf(priv->out + len, priv->out_len - len, + spec->str, arg_val); + } else if (spec->type =3D=3D PRINT_FMT_SPEC_TYPE_INT) { + switch (spec->len) { + case PRINT_FMT_SPEC_LEN_INT: + len +=3D snprintf(priv->out + len, priv->out_len - len, + spec->str, *(unsigned int *)arg_val); + break; + case PRINT_FMT_SPEC_LEN_LONG: + len +=3D snprintf(priv->out + len, priv->out_len - len, + spec->str, *(unsigned long *)arg_val); + break; + case PRINT_FMT_SPEC_LEN_LONG_LONG: + len +=3D snprintf(priv->out + len, priv->out_len - len, + spec->str, *(unsigned long long *)arg_val); + break; + default: + break; + } + } + } + + if (len >=3D priv->out_len) { + buf_out =3D realloc(priv->out, priv->out_len << 1); + if (buf_out !=3D NULL) { + priv->out =3D buf_out; + priv->out_len <<=3D 1; + goto retry; + } + } + + if (len >=3D priv->out_len) + break; + } + + printf("%s", priv->out); + return 0; +} + +static struct evtact_expr_ops expr_call_print_ops =3D { + .new =3D expr_call_print_new, + .free =3D expr_call_print_free, + .eval =3D expr_call_print_eval, +}; + static struct evtact_expr_ops *expr_call_ops_list[EVTACT_EXPR_CALL_TYPE_MA= X] =3D { + [EVTACT_EXPR_CALL_TYPE_PRINT] =3D &expr_call_print_ops, }; =20 static int expr_call_set_ops(struct evtact_expr *expr, u32 opcode) diff --git a/tools/perf/util/parse-action.h b/tools/perf/util/parse-action.h index 30c2fd6e81d0..f8aece601a84 100644 --- a/tools/perf/util/parse-action.h +++ b/tools/perf/util/parse-action.h @@ -21,6 +21,7 @@ enum evtact_expr_const_type { }; =20 enum evtact_expr_call_type { + EVTACT_EXPR_CALL_TYPE_PRINT, EVTACT_EXPR_CALL_TYPE_MAX, }; =20 diff --git a/tools/perf/util/parse-action.l b/tools/perf/util/parse-action.l index 189f73dfc3b1..5e75383ba3e7 100644 --- a/tools/perf/util/parse-action.l +++ b/tools/perf/util/parse-action.l @@ -76,6 +76,12 @@ static int str_end(void) return STRING; } =20 +static int call(u32 opcode) +{ + parse_action_lval.opcode =3D opcode; + return CALL; +} + %} =20 num_dec [0-9]+ @@ -91,6 +97,9 @@ ident [_a-zA-Z][_a-zA-Z0-9]* {num_hex} { return value(16); } {space} { } =20 + +print { return call(EVTACT_EXPR_CALL_TYPE_PRINT); } + ";" { return SEMI; } "(" { return LP; } ")" { return RP; } --=20 2.25.1