summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/expr.l
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@kernel.org>2026-08-14 15:43:51 -0700
committerPaul E. McKenney <paulmck@kernel.org>2026-08-14 15:43:51 -0700
commit9cc63f8bcd560c760d0b12e15bba8f81c86237cf (patch)
tree3b5269b1bcf6714171754946367c51e0590f64da /tools/perf/util/expr.l
downloadlinux-stable-9cc63f8bcd560c760d0b12e15bba8f81c86237cf.tar.gz
linux-stable-9cc63f8bcd560c760d0b12e15bba8f81c86237cf.zip
Merge branches 'expcb.2026.07.24a', 'misc.2026.07.30a', 'rcu-tasks.2026.07.30a', 'srcu.2026.08.11a' and 'torture.2026.08.14a' into HEADgrafted
Changes: Make expedited grace periods expedite normal RCU callbacks Miscellaneous fixes: * Improve diagnostic output with character task states. * Mark accesses to inform KCSAN of concurrency design. * Move from kmalloc() to kmalloc_obj(). * Documentation updates. * Improve handling of RCU deferred quiescent states. * Clean up unused function arguments and structure fields. * Reduce show_rcu_gp_kthreads() stack space. Tasks RCU updates: * Clean up after SRCU re-implementation of Tasks Trace RCU. * Mark accesses to inform KCSAN of concurrency design. * Add ->lazy_timer status to diagnostic output. * Remove an unnecessary memory barrier. * Fix a data race, courtesy of KCSAN. * Documentation updates. * Convert cond_resched_tasks_rcu_qs() from macro to static inline function. SRCU updates: * Add Rust helpers for SRCU. * Avoid losing queued work at cleanup_srcu_struct() time. Torture-test updates: * Preparation work for immediate RCU priority deboosting. * Test RCU readers from real interrupt handlers (as opposed to softirq). * Simplify code through use of cpumask_next_wrap(). * Improve diagnostic output with character task states. * Add rcutorture.nwriters parameter to allow lightweight stall testing, and rcutorture.stall_only to make doing so easier. * Test an RCU Tasks Trace grace period implying an RCU grace period. * Make RCU Tasks Trace torturing track reader batches. * Fix a data race, courtesy of KCSAN. * Plug a shuffle_tmp_mask memory leak on kthread spawn failure.
Diffstat (limited to 'tools/perf/util/expr.l')
-rw-r--r--tools/perf/util/expr.l150
1 files changed, 150 insertions, 0 deletions
diff --git a/tools/perf/util/expr.l b/tools/perf/util/expr.l
new file mode 100644
index 000000000..f16ccff27
--- /dev/null
+++ b/tools/perf/util/expr.l
@@ -0,0 +1,150 @@
+%option prefix="expr_"
+%option reentrant
+%option bison-bridge
+
+%{
+#include <linux/compiler.h>
+#include "expr.h"
+#include "expr-bison.h"
+#include <math.h>
+
+char *expr_get_text(yyscan_t yyscanner);
+YYSTYPE *expr_get_lval(yyscan_t yyscanner);
+
+static double __value(YYSTYPE *yylval, char *str, int token)
+{
+ double num;
+
+ errno = 0;
+ num = strtod(str, NULL);
+ if (errno)
+ return EXPR_ERROR;
+
+ yylval->num = num;
+ return token;
+}
+
+static int value(yyscan_t scanner)
+{
+ YYSTYPE *yylval = expr_get_lval(scanner);
+ char *text = expr_get_text(scanner);
+
+ return __value(yylval, text, NUMBER);
+}
+
+/*
+ * Allow @ instead of / to be able to specify pmu/event/ without
+ * conflicts with normal division.
+ */
+static char *normalize(char *str, int runtime)
+{
+ char *ret = str;
+ char *dst = str;
+
+ while (*str) {
+ if (*str == '\\') {
+ *dst++ = *++str;
+ if (!*str)
+ break;
+ }
+ else if (*str == '?') {
+ char *paramval;
+ int i = 0;
+ int size = asprintf(&paramval, "%d", runtime);
+
+ if (size < 0)
+ *dst++ = '0';
+ else {
+ while (i < size)
+ *dst++ = paramval[i++];
+ free(paramval);
+ }
+ }
+ else
+ *dst++ = *str;
+ str++;
+ }
+
+ *dst = 0x0;
+ return ret;
+}
+
+static int str(yyscan_t scanner, int token, int runtime)
+{
+ YYSTYPE *yylval = expr_get_lval(scanner);
+ char *text = expr_get_text(scanner);
+
+ yylval->str = normalize(strdup(text), runtime);
+ if (!yylval->str)
+ return EXPR_ERROR;
+
+ yylval->str = normalize(yylval->str, runtime);
+ return token;
+}
+
+static int literal(yyscan_t scanner, const struct expr_scanner_ctx *sctx)
+{
+ YYSTYPE *yylval = expr_get_lval(scanner);
+
+ yylval->num = expr__get_literal(expr_get_text(scanner), sctx);
+ if (isnan(yylval->num)) {
+ if (!sctx->is_test)
+ return EXPR_ERROR;
+ yylval->num = 1;
+ }
+ return LITERAL;
+}
+
+static int nan_value(yyscan_t scanner)
+{
+ YYSTYPE *yylval = expr_get_lval(scanner);
+
+ yylval->num = NAN;
+ return NUMBER;
+}
+%}
+
+number ([0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+)(e-?[0-9]+)?
+
+sch [-,=]
+spec \\{sch}
+sym [0-9a-zA-Z_\.:@?]+
+symbol ({spec}|{sym})+
+literal #[0-9a-zA-Z_\.\-]+
+
+%%
+ struct expr_scanner_ctx *sctx = expr_get_extra(yyscanner);
+
+d_ratio { return D_RATIO; }
+max { return MAX; }
+min { return MIN; }
+if { return IF; }
+else { return ELSE; }
+source_count { return SOURCE_COUNT; }
+aggr_nr { return AGGR_NR; }
+has_event { return HAS_EVENT; }
+strcmp_cpuid_str { return STRCMP_CPUID_STR; }
+NaN { return nan_value(yyscanner); }
+{literal} { return literal(yyscanner, sctx); }
+{number} { return value(yyscanner); }
+{symbol} { return str(yyscanner, ID, sctx->runtime); }
+"|" { return '|'; }
+"^" { return '^'; }
+"&" { return '&'; }
+"<" { return '<'; }
+">" { return '>'; }
+"-" { return '-'; }
+"+" { return '+'; }
+"*" { return '*'; }
+"/" { return '/'; }
+"%" { return '%'; }
+"(" { return '('; }
+")" { return ')'; }
+"," { return ','; }
+. { }
+%%
+
+int expr_wrap(void *scanner __maybe_unused)
+{
+ return 1;
+}