From patchwork Tue Aug 3 17:05:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491233 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CED86C43214 for ; Tue, 3 Aug 2021 17:06:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BBD8F610FE for ; Tue, 3 Aug 2021 17:06:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237931AbhHCRHA (ORCPT ); Tue, 3 Aug 2021 13:07:00 -0400 Received: from mail.kernel.org ([198.145.29.99]:38738 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237502AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id AE6DC60FA0; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubP-HU; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" , Lukas Bulwahn , Daniel Black Subject: [PATCH v3 01/22] libtracefs: Added new API tracefs_sql() Date: Tue, 3 Aug 2021 13:05:45 -0400 Message-Id: <20210803170606.694085-2-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" This adds the API tracefs_sql() that takes a tep_handle handler, a name, and a SQL string and parses it to produce a tracefs_synth synthetic event handler. Currently it only supports simple SQL of the type: SELECT start.common_pid AS pid, end.common_timestamp.usecs AS usecs FROM sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid Special thanks to: Lukas Bulwahn for first introducing the idea at RT Summit on the Summit Spring of 2019. Daniel Black for sorting out the syntax of mapping the synthetic event creations into SQL statements at Linux Plumbers, Fall of 2019. Cc: Lukas Bulwahn Cc: Daniel Black Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 3 + src/Makefile | 13 + src/sqlhist-parse.h | 69 ++++ src/sqlhist.l | 88 +++++ src/sqlhist.y | 143 ++++++++ src/tracefs-sqlhist.c | 756 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1072 insertions(+) create mode 100644 src/sqlhist-parse.h create mode 100644 src/sqlhist.l create mode 100644 src/sqlhist.y create mode 100644 src/tracefs-sqlhist.c diff --git a/include/tracefs.h b/include/tracefs.h index 55f82392b004..219adba4b0ce 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -477,4 +477,7 @@ void tracefs_synth_free(struct tracefs_synth *synth); int tracefs_synth_show(struct trace_seq *seq, struct tracefs_instance *instance, struct tracefs_synth *synth); +struct tracefs_synth *tracefs_sql(struct tep_handle *tep, const char *name, + const char *sql_buffer, char **err); + #endif /* _TRACE_FS_H */ diff --git a/src/Makefile b/src/Makefile index 767af49034ee..9248efc5c7fd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,6 +12,11 @@ OBJS += tracefs-kprobes.o OBJS += tracefs-hist.o OBJS += tracefs-filter.o +# Order matters for the the three below +OBJS += sqlhist-lex.o +OBJS += sqlhist.tab.o +OBJS += tracefs-sqlhist.o + OBJS := $(OBJS:%.o=$(bdir)/%.o) DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) @@ -32,6 +37,14 @@ $(LIBTRACEFS_SHARED_SO): $(LIBTRACEFS_SHARED_VERSION) libtracefs.so: $(LIBTRACEFS_SHARED_SO) +# bison will create both sqlhist.tab.c and sqlhist.tab.h +sqlhist.tab.h: +sqlhist.tab.c: sqlhist.y sqlhist.tab.h + bison --debug -v --report-file=bison.report -d -o $@ $< + +sqlhist-lex.c: sqlhist.l sqlhist.tab.c + flex -o $@ $< + $(bdir)/%.o: %.c $(Q)$(call do_fpic_compile) diff --git a/src/sqlhist-parse.h b/src/sqlhist-parse.h new file mode 100644 index 000000000000..aa5232eea451 --- /dev/null +++ b/src/sqlhist-parse.h @@ -0,0 +1,69 @@ +#ifndef __SQLHIST_PARSE_H +#define __SQLHIST_PARSE_H + +#include +#include + +struct str_hash; +#define HASH_BITS 10 + +struct sql_table; + +struct sqlhist_bison { + const char *buffer; + size_t buffer_size; + size_t buffer_idx; + int line_no; + int line_idx; + struct sql_table *table; + char *parse_error_str; + struct str_hash *str_hash[1 << HASH_BITS]; +}; + +extern struct sqlhist_bison *sb; + +#include "sqlhist.tab.h" + +enum filter_type { + FILTER_GROUP, + FILTER_NOT_GROUP, + FILTER_EQ, + FILTER_NE, + FILTER_LE, + FILTER_LT, + FILTER_GE, + FILTER_GT, + FILTER_BIN_AND, + FILTER_STR_CMP, + FILTER_AND, + FILTER_OR, +}; + +enum compare_type { + COMPARE_GROUP, + COMPARE_ADD, + COMPARE_SUB, + COMPARE_MUL, + COMPARE_DIV, + COMPARE_BIN_AND, + COMPARE_BIN_OR, + COMPARE_AND, + COMPARE_OR, +}; + +char * store_str(struct sqlhist_bison *sb, const char *str); + +int table_start(struct sqlhist_bison *sb); + +void *add_field(struct sqlhist_bison *sb, const char *field, const char *label); + +int add_match(struct sqlhist_bison *sb, void *A, void *B); + +int add_selection(struct sqlhist_bison *sb, void *item, const char *label); +int add_from(struct sqlhist_bison *sb, void *item); +int add_to(struct sqlhist_bison *sb, void *item); + +extern void sql_parse_error(struct sqlhist_bison *sb, const char *text, + const char *fmt, va_list ap); + +#endif diff --git a/src/sqlhist.l b/src/sqlhist.l new file mode 100644 index 000000000000..5dfd17517c6e --- /dev/null +++ b/src/sqlhist.l @@ -0,0 +1,88 @@ +%{ +/* code here */ + +#include +#include "sqlhist-parse.h" + +extern int my_yyinput(char *buf, int max); + +#undef YY_INPUT +#define YY_INPUT(b, r, m) ({r = my_yyinput(b, m);}) + +#define YY_NO_INPUT +#define YY_NO_UNPUT + +#define YY_EXTRA_TYPE struct sqlhist_bison * + +#define HANDLE_COLUMN do { sb->line_idx += strlen(yytext); } while (0) + +%} + +%option caseless + +field [a-z_][a-z0-9_\.]* +qstring \"[^\"]*\" +hexnum 0x[0-9a-f]+ +number [0-9a-f]+ + +%% + +select { HANDLE_COLUMN; return SELECT; } +as { HANDLE_COLUMN; return AS; } +from { HANDLE_COLUMN; return FROM; } +join { HANDLE_COLUMN; return JOIN; } +on { HANDLE_COLUMN; return ON; } + +{qstring} { + HANDLE_COLUMN; + yylval.string = store_str(sb, yytext); + return STRING; +} + +{field} { + HANDLE_COLUMN; + yylval.string = store_str(sb, yytext); + return FIELD; +} + +{hexnum} { + HANDLE_COLUMN; + yylval.number = strtol(yytext, NULL, 0); + return NUMBER; +} + +{number} { + HANDLE_COLUMN; + yylval.number = strtol(yytext, NULL, 0); + return NUMBER; +} + +\!= { HANDLE_COLUMN; return NEQ; } +\<= { HANDLE_COLUMN; return LE; } +\>= { HANDLE_COLUMN; return GE; } +== { HANDLE_COLUMN; return EQ; } +&& { HANDLE_COLUMN; return AND; } +"||" { HANDLE_COLUMN; return OR; } +[<>&~] { HANDLE_COLUMN; return yytext[0]; } + +[\!()\-\+\*/,=] { HANDLE_COLUMN; return yytext[0]; } + +[ \t] { HANDLE_COLUMN; } +\n { sb->line_idx = 0; sb->line_no++; } + +. { HANDLE_COLUMN; return PARSE_ERROR; } +%% + +int yywrap(void) +{ + return 1; +} + +void yyerror(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sql_parse_error(sb, yytext, fmt, ap); + va_end(ap); +} diff --git a/src/sqlhist.y b/src/sqlhist.y new file mode 100644 index 000000000000..ecb0a0ed44b3 --- /dev/null +++ b/src/sqlhist.y @@ -0,0 +1,143 @@ +%{ +#include +#include +#include +#include + +#include "sqlhist-parse.h" + +extern int yylex(void); +extern void yyerror(char *fmt, ...); + +#define CHECK_RETURN_PTR(x) \ + do { \ + if (!(x)) { \ + printf("FAILED MEMORY: %s\n", #x); \ + return -ENOMEM; \ + } \ + } while (0) + +#define CHECK_RETURN_VAL(x) \ + do { \ + if ((x) < 0) { \ + printf("FAILED MEMORY: %s\n", #x); \ + return -ENOMEM; \ + } \ + } while (0) + +%} + +%union { + int s32; + char *string; + long number; + void *expr; +} + +%token AS SELECT FROM JOIN ON PARSE_ERROR +%token NUMBER +%token STRING +%token FIELD +%token LE GE EQ NEQ AND OR + +%left '+' '-' +%left '*' '/' +%left '<' '>' +%left AND OR + +%type name label + +%type selection_expr field item named_field join_clause + +%% + +start : + select_statement + ; + +label : AS name { CHECK_RETURN_PTR($$ = store_str(sb, $2)); } + | name { CHECK_RETURN_PTR($$ = store_str(sb, $1)); } + ; + +select : SELECT { table_start(sb); } + ; + +select_statement : + select selection_list table_exp + ; + +selection_list : + selection + | selection ',' selection_list + ; + +selection : + selection_expr + { + CHECK_RETURN_VAL(add_selection(sb, $1, NULL)); + } + | selection_expr label + { + CHECK_RETURN_VAL(add_selection(sb, $1, $2)); + } + ; + +selection_expr : + field + | '(' field ')' { $$ = $2; } + ; + +item : + named_field + | field + ; + +field : + FIELD { $$ = add_field(sb, $1, NULL); CHECK_RETURN_PTR($$); } + ; + +named_field : + FIELD label { $$ = add_field(sb, $1, $2); CHECK_RETURN_PTR($$); } + ; + +name : + FIELD + ; + +table_exp : + from_clause join_clause + ; + +from_clause : + FROM item { CHECK_RETURN_VAL(add_from(sb, $2)); } + +/* + * Select from a from clause confuses the variable parsing. + * disable it for now. + + | FROM '(' select_statement ')' label + { + from_table_end($5); + $$ = store_printf("FROM (%s) AS %s", $3, $5); + } +*/ + ; + +join_clause : + JOIN item ON match_clause { add_to(sb, $2); } + ; + +match : + item '=' item { CHECK_RETURN_VAL(add_match(sb, $1, $3)); } + | item EQ item { CHECK_RETURN_VAL(add_match(sb, $1, $3)); } + + ; + +match_clause : + match + | match ',' match_clause + ; + +%% + + diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c new file mode 100644 index 000000000000..5f2729325c1c --- /dev/null +++ b/src/tracefs-sqlhist.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2021 VMware Inc, Steven Rostedt + * + * Updates: + * Copyright (C) 2021, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include + +#include "tracefs.h" +#include "tracefs-local.h" +#include "sqlhist-parse.h" + +struct sqlhist_bison *sb; + +extern int yylex_init(void* ptr_yy_globals); +extern int yylex_init_extra(struct sqlhist_bison *sb, void* ptr_yy_globals); +extern int yylex_destroy (void * yyscanner ); + +struct str_hash { + struct str_hash *next; + char *str; +}; + +enum alias_type { + ALIAS_EVENT, + ALIAS_FIELD, +}; + +#define for_each_field(expr, field, table) \ + for (expr = (table)->fields; expr; expr = (field)->next) + +struct field { + struct expr *next; /* private link list */ + const char *system; + const char *event_name; + struct tep_event *event; + const char *raw; + const char *label; + const char *field; +}; + +struct match { + struct match *next; + struct expr *lval; + struct expr *rval; +}; + +enum expr_type +{ + EXPR_NUMBER, + EXPR_STRING, + EXPR_FIELD, +}; + +struct expr { + struct expr *free_list; + struct expr *next; + enum expr_type type; + union { + struct field field; + const char *string; + long number; + }; +}; + +struct sql_table { + struct sqlhist_bison *sb; + const char *name; + struct expr *exprs; + struct expr *fields; + struct expr *from; + struct expr *to; + struct match *matches; + struct match **next_match; + struct expr *selections; + struct expr **next_selection; +}; + +__hidden int my_yyinput(char *buf, int max) +{ + if (!sb || !sb->buffer) + return -1; + + if (sb->buffer_idx + max > sb->buffer_size) + max = sb->buffer_size - sb->buffer_idx; + + if (max) + memcpy(buf, sb->buffer + sb->buffer_idx, max); + + sb->buffer_idx += max; + + return max; +} + +__hidden void sql_parse_error(struct sqlhist_bison *sb, const char *text, + const char *fmt, va_list ap) +{ + const char *buffer = sb->buffer; + struct trace_seq s; + int line = sb->line_no; + int idx = sb->line_idx - strlen(text); + int i; + + if (!buffer) + return; + + trace_seq_init(&s); + if (!s.buffer) { + fprintf(stderr, "Error allocating internal buffer\n"); + return; + } + + for (i = 0; line && buffer[i]; i++) { + if (buffer[i] == '\n') + line--; + } + for (; buffer[i] && buffer[i] != '\n'; i++) + trace_seq_putc(&s, buffer[i]); + trace_seq_putc(&s, '\n'); + for (i = idx; i > 0; i--) + trace_seq_putc(&s, ' '); + trace_seq_puts(&s, "^\n"); + trace_seq_printf(&s, "ERROR: '%s'\n", text); + trace_seq_vprintf(&s, fmt, ap); + + trace_seq_terminate(&s); + + sb->parse_error_str = strdup(s.buffer); + trace_seq_destroy(&s); +} + +static inline unsigned int quick_hash(const char *str) +{ + unsigned int val = 0; + int len = strlen(str); + + for (; len >= 4; str += 4, len -= 4) { + val += str[0]; + val += str[1] << 8; + val += str[2] << 16; + val += str[3] << 24; + } + for (; len > 0; str++, len--) + val += str[0] << (len * 8); + + val *= 2654435761; + + return val & ((1 << HASH_BITS) - 1); +} + + +static struct str_hash *find_string(struct sqlhist_bison *sb, const char *str) +{ + unsigned int key = quick_hash(str); + struct str_hash *hash = sb->str_hash[key]; + + for (; hash; hash = hash->next) { + if (!strcmp(hash->str, str)) + return hash; + } + return NULL; +} + +/* + * If @str is found, then return the hash string. + * This lets store_str() know to free str. + */ +static char **add_hash(struct sqlhist_bison *sb, const char *str) +{ + struct str_hash *hash; + unsigned int key; + + if ((hash = find_string(sb, str))) { + return &hash->str; + } + + hash = malloc(sizeof(*hash)); + if (!hash) + return NULL; + key = quick_hash(str); + hash->next = sb->str_hash[key]; + sb->str_hash[key] = hash; + hash->str = NULL; + return &hash->str; +} + +__hidden char *store_str(struct sqlhist_bison *sb, const char *str) +{ + char **pstr = add_hash(sb, str); + + if (!pstr) + return NULL; + + if (!(*pstr)) + *pstr = strdup(str); + + return *pstr; +} + +__hidden int add_selection(struct sqlhist_bison *sb, void *select, + const char *name) +{ + struct sql_table *table = sb->table; + struct expr *expr = select; + + switch (expr->type) { + case EXPR_FIELD: + break; + case EXPR_NUMBER: + case EXPR_STRING: + default: + return -1; + } + + if (expr->next) + return -1; + + *table->next_selection = expr; + table->next_selection = &expr->next; + + return 0; +} + +static struct expr *find_field(struct sqlhist_bison *sb, + const char *raw, const char *label) +{ + struct field *field; + struct expr *expr; + + for_each_field(expr, field, sb->table) { + field = &expr->field; + + if (!strcmp(field->raw, raw)) { + if (label && !field->label) + field->label = label; + return expr; + } + + if (label && !strcmp(field->raw, label)) { + if (!field->label) { + field->label = label; + field->raw = raw; + } + return expr; + } + + if (!field->label) + continue; + + if (!strcmp(field->label, raw)) + return expr; + + if (label && !strcmp(field->label, label)) + return expr; + } + return NULL; +} + +static void *create_expr(enum expr_type type, struct expr **expr_p) +{ + struct expr *expr; + + expr = calloc(1, sizeof(*expr)); + if (!expr) + return NULL; + + if (expr_p) + *expr_p = expr; + + expr->free_list = sb->table->exprs; + sb->table->exprs = expr; + + expr->type = type; + + switch (type) { + case EXPR_FIELD: return &expr->field; + case EXPR_NUMBER: return &expr->number; + case EXPR_STRING: return &expr->string; + } + + return NULL; +} + +#define __create_expr(var, type, ENUM, expr) \ + do { \ + var = (type *)create_expr(EXPR_##ENUM, expr); \ + } while(0) + +#define create_field(var, expr) \ + __create_expr(var, struct field, FIELD, expr) + +__hidden void *add_field(struct sqlhist_bison *sb, + const char *field_name, const char *label) +{ + struct sql_table *table = sb->table; + struct expr *expr; + struct field *field; + + expr = find_field(sb, field_name, label); + if (expr) + return expr; + + create_field(field, &expr); + + field->next = table->fields; + table->fields = expr; + + field->raw = field_name; + field->label = label; + + return expr; +} + +__hidden int add_match(struct sqlhist_bison *sb, void *A, void *B) +{ + struct sql_table *table = sb->table; + struct match *match; + + match = calloc(1, sizeof(*match)); + if (!match) + return -1; + + match->lval = A; + match->rval = B; + + *table->next_match = match; + table->next_match = &match->next; + + return 0; +} + +__hidden int add_from(struct sqlhist_bison *sb, void *item) +{ + struct expr *expr = item; + + if (expr->type != EXPR_FIELD) + return -1; + + sb->table->from = expr; + + return 0; +} + +__hidden int add_to(struct sqlhist_bison *sb, void *item) +{ + struct expr *expr = item; + + if (expr->type != EXPR_FIELD) + return -1; + + sb->table->to = expr; + + return 0; +} + +__hidden int table_start(struct sqlhist_bison *sb) +{ + struct sql_table *table; + + table = calloc(1, sizeof(*table)); + if (!table) + return -ENOMEM; + + table->sb = sb; + sb->table = table; + + table->next_match = &table->matches; + table->next_selection = &table->selections; + + return 0; +} + +static int test_event_exists(struct tep_handle *tep, + struct expr *expr, struct tep_event **pevent) +{ + struct field *field = &expr->field; + const char *system = field->system; + const char *event = field->event_name; + + if (!field->event) + field->event = tep_find_event_by_name(tep, system, event); + if (pevent) + *pevent = field->event; + return field->event != NULL ? 0 : -1; +} + +static int test_field_exists(struct expr *expr) +{ + struct field *field = &expr->field; + struct tep_format_field *tfield; + char *field_name; + const char *p; + + if (!field->event) + return -1; + + /* The field could have a conversion */ + p = strchr(field->field, '.'); + if (p) + field_name = strndup(field->field, p - field->field); + else + field_name = strdup(field->field); + + if (!field_name) + return -1; + + if (!strcmp(field_name, TRACEFS_TIMESTAMP) || + !strcmp(field->field, TRACEFS_TIMESTAMP_USECS)) + tfield = (void *)1L; + else + tfield = tep_find_any_field(field->event, field_name); + free(field_name); + + return tfield != NULL ? 0 : -1; +} + +static int update_vars(struct tep_handle *tep, + struct sql_table *table, + struct expr *expr) +{ + struct sqlhist_bison *sb = table->sb; + struct field *event_field = &expr->field; + struct tep_event *event; + struct field *field; + const char *label; + const char *raw = event_field->raw; + const char *event_name; + const char *system; + const char *p; + int label_len = 0, event_len, system_len; + + p = strchr(raw, '.'); + if (p) { + char *str; + + str = strndup(raw, p - raw); + if (!str) + return -1; + event_field->system = store_str(sb, str); + free(str); + if (!event_field->system) + return -1; + p++; + } else { + p = raw; + } + + event_field->event_name = store_str(sb, p); + if (!event_field->event_name) + return -1; + + if (test_event_exists(tep, expr, &event)) + return -1; + + if (!event_field->system) + event_field->system = store_str(sb, event->system); + + if (!event_field->system) + return -1; + + label = event_field->label; + if (label) + label_len = strlen(label); + + system = event_field->system; + system_len = strlen(system); + + event_name = event_field->event_name; + event_len = strlen(event_name); + + for_each_field(expr, field, table) { + int len; + + field = &expr->field; + + if (field->event) + continue; + + raw = field->raw; + + /* + * The field could be: + * system.event.field... + * event.field... + * label.field... + * We check label first. + */ + + len = label_len; + if (label && !strncmp(raw, label, len) && + raw[len] == '.') { + /* Label matches and takes precedence */ + goto found; + } + + if (!strncmp(raw, system, system_len) && + raw[system_len] == '.') { + raw += system_len + 1; + /* Check the event portion next */ + } + + len = event_len; + if (strncmp(raw, event_name, len) || + raw[len] != '.') { + /* Does not match */ + continue; + } + found: + field->system = system; + field->event_name = event_name; + field->event = event; + field->field = raw + len + 1; + + if (!strcmp(field->field, "TIMESTAMP")) + field->field = store_str(sb, TRACEFS_TIMESTAMP); + if (!strcmp(field->field, "TIMESTAMP_USECS")) + field->field = store_str(sb, TRACEFS_TIMESTAMP_USECS); + if (test_field_exists(expr)) + return -1; + } + + return 0; +} + +static int test_match(struct sql_table *table, struct match *match) +{ + struct field *lval, *rval; + struct field *to, *from; + + if (!match->lval || !match->rval) + return -1; + + if (match->lval->type != EXPR_FIELD || match->rval->type != EXPR_FIELD) + return -1; + + to = &table->to->field; + from = &table->from->field; + + lval = &match->lval->field; + rval = &match->rval->field; + + /* + * Note, strings are stored in the string store, so all + * duplicate strings are the same value, and we can use + * normal "==" and "!=" instead of strcmp(). + * + * Either lval == to and rval == from + * or lval == from and rval == to. + */ + if ((lval->system != to->system) || + (lval->event != to->event)) { + if ((rval->system != to->system) || + (rval->event != to->event) || + (lval->system != from->system) || + (lval->event != from->event)) + return -1; + } else { + if ((rval->system != from->system) || + (rval->event != from->event) || + (lval->system != to->system) || + (lval->event != to->event)) + return -1; + } + return 0; +} + +static void assign_match(const char *system, const char *event, + struct match *match, + const char **start_match, const char **end_match) +{ + struct field *lval, *rval; + + lval = &match->lval->field; + rval = &match->rval->field; + + if (lval->system == system && + lval->event_name == event) { + *start_match = lval->field; + *end_match = rval->field; + } else { + *start_match = rval->field; + *end_match = lval->field; + } +} + +static struct tracefs_synth *build_synth(struct tep_handle *tep, + const char *name, + struct sql_table *table) +{ + struct tracefs_synth *synth; + struct field *field; + struct match *match; + struct expr *expr; + const char *start_system; + const char *start_event; + const char *end_system; + const char *end_event; + const char *start_match; + const char *end_match; + int ret; + + if (!table->to || !table->from) + return NULL; + + ret = update_vars(tep, table, table->to); + if (ret < 0) + return NULL; + + ret = update_vars(tep, table, table->from); + if (ret < 0) + return NULL; + + match = table->matches; + if (!match) + return NULL; + + ret = test_match(table, match); + if (ret < 0) + return NULL; + + start_system = table->from->field.system; + start_event = table->from->field.event_name; + + end_system = table->to->field.system; + end_event = table->to->field.event_name; + + assign_match(start_system, start_event, match, + &start_match, &end_match); + + synth = tracefs_synth_init(tep, name, start_system, + start_event, end_system, end_event, + start_match, end_match, NULL); + if (!synth) + return NULL; + + for (match = match->next; match; match = match->next) { + ret = test_match(table, match); + if (ret < 0) + goto free; + + assign_match(start_system, start_event, match, + &start_match, &end_match); + + ret = tracefs_synth_add_match_field(synth, + start_match, + end_match, NULL); + if (ret < 0) + goto free; + } + + for (expr = table->selections; expr; expr = expr->next) { + if (expr->type == EXPR_FIELD) { + field = &expr->field; + if (field->system == start_system && + field->event_name == start_event) { + ret = tracefs_synth_add_start_field(synth, + field->field, field->label); + } else { + ret = tracefs_synth_add_end_field(synth, + field->field, field->label); + } + if (ret < 0) + goto free; + continue; + } + goto free; + } + + return synth; + free: + tracefs_synth_free(synth); + return NULL; +} + +static void free_sql_table(struct sql_table *table) +{ + struct match *match; + struct expr *expr; + + if (!table) + return; + + while ((expr = table->exprs)) { + table->exprs = expr->next; + free(expr); + } + + while ((match = table->matches)) { + table->matches = match->next; + free(match); + } + + free(table); +} + +static void free_str_hash(struct str_hash **hash) +{ + struct str_hash *item; + int i; + + for (i = 0; i < 1 << HASH_BITS; i++) { + while ((item = hash[i])) { + hash[i] = item->next; + free(item->str); + free(item); + } + } +} + +static void free_sb(struct sqlhist_bison *sb) +{ + free_sql_table(sb->table); + free_str_hash(sb->str_hash); + free(sb->parse_error_str); +} + +struct tracefs_synth *tracefs_sql(struct tep_handle *tep, const char *name, + const char *sql_buffer, char **err) +{ + struct sqlhist_bison local_sb; + struct tracefs_synth *synth = NULL; + int ret; + + if (!tep || !sql_buffer) { + errno = EINVAL; + return NULL; + } + + memset(&local_sb, 0, sizeof(local_sb)); + + local_sb.buffer = sql_buffer; + local_sb.buffer_size = strlen(sql_buffer); + local_sb.buffer_idx = 0; + + sb = &local_sb; + ret = yyparse(); + + if (ret) + goto free; + + synth = build_synth(tep, name, sb->table); + + free: + if (!synth) { + if (sb->parse_error_str && err) { + *err = sb->parse_error_str; + sb->parse_error_str = NULL; + } + } + free_sb(sb); + return synth; +} From patchwork Tue Aug 3 17:05:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491242 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1B106C19F31 for ; Tue, 3 Aug 2021 17:06:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F07356104F for ; Tue, 3 Aug 2021 17:06:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237594AbhHCRGX (ORCPT ); Tue, 3 Aug 2021 13:06:23 -0400 Received: from mail.kernel.org ([198.145.29.99]:38558 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234376AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id AE93361029; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubR-Iu; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 02/22] tracefs: Add unit tests for tracefs_sql() Date: Tue, 3 Aug 2021 13:05:46 -0400 Message-Id: <20210803170606.694085-3-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add basic unit test for tracefs_sql()... Signed-off-by: Steven Rostedt (VMware) --- utest/tracefs-utest.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 2a99217b938a..89bb1cce61f7 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -44,6 +44,12 @@ #define KRETPROBE_ADDR "do_sys_openat2" #define KRETPROBE_FMT "ret=$retval" +#define SQL_1_EVENT "wakeup_1" +#define SQL_1_SQL "select sched_switch.next_pid as woke_pid, sched_waking.common_pid as waking_pid from sched_waking join sched_switch on sched_switch.next_pid = sched_waking.pid" + +#define SQL_2_EVENT "wakeup_2" +#define SQL_2_SQL "select woke.next_pid as woke_pid, wake.common_pid as waking_pid from sched_waking as wake join sched_switch as woke on woke.next_pid = wake.pid" + static struct tracefs_instance *test_instance; static struct tep_handle *test_tep; struct test_sample { @@ -322,6 +328,41 @@ static void test_ftrace_marker(void) test_instance_ftrace_marker(test_instance); } +static void test_instance_trace_sql(struct tracefs_instance *instance) +{ + struct tracefs_synth *synth; + struct trace_seq seq; + struct tep_handle *tep; + int ret; + + tep = tracefs_local_events(NULL); + CU_TEST(tep != NULL); + + trace_seq_init(&seq); + + synth = tracefs_sql(tep, SQL_1_EVENT, SQL_1_SQL, NULL); + CU_TEST(synth != NULL); + ret = tracefs_synth_show(&seq, instance, synth); + CU_TEST(ret == 0); + tracefs_synth_free(synth); + trace_seq_reset(&seq); + + synth = tracefs_sql(tep, SQL_2_EVENT, SQL_2_SQL, NULL); + CU_TEST(synth != NULL); + ret = tracefs_synth_show(&seq, instance, synth); + CU_TEST(ret == 0); + tracefs_synth_free(synth); + trace_seq_reset(&seq); + + tep_free(tep); + trace_seq_destroy(&seq); +} + +static void test_trace_sql(void) +{ + test_instance_trace_sql(test_instance); +} + static void test_trace_file(void) { const char *tmp = get_rand_str(); @@ -1338,6 +1379,8 @@ void test_tracefs_lib(void) fprintf(stderr, "Suite \"%s\" cannot be ceated\n", TRACEFS_SUITE); return; } + CU_add_test(suite, "trace sql", + test_trace_sql); CU_add_test(suite, "tracing file / directory APIs", test_trace_file); CU_add_test(suite, "instance file / directory APIs", From patchwork Tue Aug 3 17:05:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491237 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2B5FC4320A for ; Tue, 3 Aug 2021 17:06:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A3DE5610CC for ; Tue, 3 Aug 2021 17:06:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237570AbhHCRGV (ORCPT ); Tue, 3 Aug 2021 13:06:21 -0400 Received: from mail.kernel.org ([198.145.29.99]:38584 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234792AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id AFAB761037; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubV-Ju; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 03/22] libtracefs: Add comparing start and end fields in tracefs_sql() Date: Tue, 3 Aug 2021 13:05:47 -0400 Message-Id: <20210803170606.694085-4-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add comparing a field and showing the differences between start and end for tracefs_sql(). For example: SELECT (end.common_timestamp.usecs - start.common_timestamp.usecs) AS lat FROM sched_waking AS start JOIN sched_switch AS end ON start.pid = stop.next_pid Signed-off-by: Steven Rostedt (VMware) --- src/sqlhist-parse.h | 1 + src/sqlhist.y | 16 ++++++++ src/tracefs-sqlhist.c | 85 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/sqlhist-parse.h b/src/sqlhist-parse.h index aa5232eea451..aeb1738d693f 100644 --- a/src/sqlhist-parse.h +++ b/src/sqlhist-parse.h @@ -58,6 +58,7 @@ int table_start(struct sqlhist_bison *sb); void *add_field(struct sqlhist_bison *sb, const char *field, const char *label); int add_match(struct sqlhist_bison *sb, void *A, void *B); +void *add_compare(struct sqlhist_bison *sb, void *A, void *B, enum compare_type type); int add_selection(struct sqlhist_bison *sb, void *item, const char *label); int add_from(struct sqlhist_bison *sb, void *item); diff --git a/src/sqlhist.y b/src/sqlhist.y index ecb0a0ed44b3..1ba3bf62ee43 100644 --- a/src/sqlhist.y +++ b/src/sqlhist.y @@ -48,6 +48,7 @@ extern void yyerror(char *fmt, ...); %type name label %type selection_expr field item named_field join_clause +%type selection_addition %% @@ -85,6 +86,21 @@ selection : selection_expr : field | '(' field ')' { $$ = $2; } + | selection_addition + | '(' selection_addition ')' { $$ = $2; } + ; + +selection_addition : + field '+' field + { + $$ = add_compare(sb, $1, $3, COMPARE_ADD); + CHECK_RETURN_PTR($$); + } + | field '-' field + { + $$ = add_compare(sb, $1, $3, COMPARE_SUB); + CHECK_RETURN_PTR($$); + } ; item : diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 5f2729325c1c..01c04211499a 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -43,17 +43,32 @@ struct field { const char *field; }; +struct filter { + enum filter_type type; + struct expr *lval; + struct expr *rval; +}; + struct match { struct match *next; struct expr *lval; struct expr *rval; }; +struct compare { + enum compare_type type; + struct expr *lval; + struct expr *rval; + const char *name; +}; + enum expr_type { EXPR_NUMBER, EXPR_STRING, EXPR_FIELD, + EXPR_FILTER, + EXPR_COMPARE, }; struct expr { @@ -62,6 +77,8 @@ struct expr { enum expr_type type; union { struct field field; + struct filter filter; + struct compare compare; const char *string; long number; }; @@ -210,8 +227,14 @@ __hidden int add_selection(struct sqlhist_bison *sb, void *select, switch (expr->type) { case EXPR_FIELD: break; + case EXPR_COMPARE: + if (!name) + return -1; + expr->compare.name = name; + break; case EXPR_NUMBER: case EXPR_STRING: + case EXPR_FILTER: default: return -1; } @@ -278,8 +301,10 @@ static void *create_expr(enum expr_type type, struct expr **expr_p) switch (type) { case EXPR_FIELD: return &expr->field; + case EXPR_COMPARE: return &expr->compare; case EXPR_NUMBER: return &expr->number; case EXPR_STRING: return &expr->string; + case EXPR_FILTER: return &expr->filter; } return NULL; @@ -293,6 +318,9 @@ static void *create_expr(enum expr_type type, struct expr **expr_p) #define create_field(var, expr) \ __create_expr(var, struct field, FIELD, expr) +#define create_compare(var, expr) \ + __create_expr(var, struct compare, COMPARE, expr) + __hidden void *add_field(struct sqlhist_bison *sb, const char *field_name, const char *label) { @@ -332,6 +360,21 @@ __hidden int add_match(struct sqlhist_bison *sb, void *A, void *B) return 0; } +__hidden void *add_compare(struct sqlhist_bison *sb, + void *A, void *B, enum compare_type type) +{ + struct compare *compare; + struct expr *expr; + + create_compare(compare, &expr); + + compare = &expr->compare; + compare->lval = A; + compare->rval = B; + compare->type = type; + + return expr; +} __hidden int add_from(struct sqlhist_bison *sb, void *item) { @@ -587,6 +630,39 @@ static void assign_match(const char *system, const char *event, } } +static int build_compare(struct tracefs_synth *synth, + const char *system, const char *event, + struct compare *compare) +{ + const char *start_field; + const char *end_field; + struct field *lval, *rval; + enum tracefs_synth_calc calc; + int ret; + + lval = &compare->lval->field; + rval = &compare->rval->field; + + if (lval->system == system && + lval->event_name == event) { + start_field = lval->field; + end_field = rval->field; + calc = TRACEFS_SYNTH_DELTA_START; + } else { + start_field = rval->field; + end_field = lval->field; + calc = TRACEFS_SYNTH_DELTA_END; + } + + if (compare->type == COMPARE_ADD) + calc = TRACEFS_SYNTH_ADD; + + ret = tracefs_synth_add_compare_field(synth, start_field, + end_field, calc, + compare->name); + return ret; +} + static struct tracefs_synth *build_synth(struct tep_handle *tep, const char *name, struct sql_table *table) @@ -667,7 +743,14 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, goto free; continue; } - goto free; + + if (expr->type != EXPR_COMPARE) + goto free; + + ret = build_compare(synth, start_system, end_system, + &expr->compare); + if (ret < 0) + goto free; } return synth; From patchwork Tue Aug 3 17:05:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491243 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C864C4320A for ; Tue, 3 Aug 2021 17:06:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1E51360EB9 for ; Tue, 3 Aug 2021 17:06:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237540AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from mail.kernel.org ([198.145.29.99]:38668 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237291AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B5B9760F70; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubY-Kq; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 04/22] libtracefs: Add unit test to test tracefs_sql() compare Date: Tue, 3 Aug 2021 13:05:48 -0400 Message-Id: <20210803170606.694085-5-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add a test to test passing time from sched_waking to sched_switch to show wake up latency. Signed-off-by: Steven Rostedt (VMware) --- utest/tracefs-utest.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 89bb1cce61f7..93bc6f16f99a 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -50,6 +50,9 @@ #define SQL_2_EVENT "wakeup_2" #define SQL_2_SQL "select woke.next_pid as woke_pid, wake.common_pid as waking_pid from sched_waking as wake join sched_switch as woke on woke.next_pid = wake.pid" +#define SQL_3_EVENT "wakeup_lat" +#define SQL_3_SQL "select sched_switch.next_prio as prio, end.prev_prio as pprio, (sched.sched_waking.common_timestamp.usecs - end.TIMESTAMP_USECS) as lat from sched_waking as start join sched_switch as end on start.pid = end.next_pid" + static struct tracefs_instance *test_instance; static struct tep_handle *test_tep; struct test_sample { @@ -354,6 +357,13 @@ static void test_instance_trace_sql(struct tracefs_instance *instance) tracefs_synth_free(synth); trace_seq_reset(&seq); + synth = tracefs_sql(tep, SQL_3_EVENT, SQL_3_SQL, NULL); + CU_TEST(synth != NULL); + ret = tracefs_synth_show(&seq, instance, synth); + CU_TEST(ret == 0); + tracefs_synth_free(synth); + trace_seq_reset(&seq); + tep_free(tep); trace_seq_destroy(&seq); } From patchwork Tue Aug 3 17:05:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491241 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89E08C19F3A for ; Tue, 3 Aug 2021 17:06:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 66CAF6104F for ; Tue, 3 Aug 2021 17:06:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237609AbhHCRGZ (ORCPT ); Tue, 3 Aug 2021 13:06:25 -0400 Received: from mail.kernel.org ([198.145.29.99]:38730 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237479AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id C1B806109F; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubk-Ol; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 08/22] libtracefs: Make parser unique to libtracefs Date: Tue, 3 Aug 2021 13:05:52 -0400 Message-Id: <20210803170606.694085-9-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add %define api.prefix and defines to have the parser global variables use tracefs_* instead of yy*, as without this, if a tool that links to this library, and tries to use the synth sql parsing, it may end up using its own yyparse() and friends functions. Signed-off-by: Steven Rostedt (VMware) --- src/sqlhist.y | 10 ++++++++++ src/tracefs-sqlhist.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sqlhist.y b/src/sqlhist.y index ce9cb58fb3a9..9d03a457ae84 100644 --- a/src/sqlhist.y +++ b/src/sqlhist.y @@ -30,6 +30,16 @@ extern void yyerror(struct sqlhist_bison *, char *fmt, ...); %} %define api.pure + +/* Change the globals to use tracefs_ prefix */ +%define api.prefix{tracefs_} +%code provides +{ + #define YYSTYPE TRACEFS_STYPE + #define yylex tracefs_lex + #define yyerror tracefs_error +} + %lex-param {void *scanner} %parse-param {struct sqlhist_bison *sb} diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 65577c9b7de3..70bcab14cb27 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -1086,7 +1086,7 @@ struct tracefs_synth *tracefs_sql(struct tep_handle *tep, const char *name, return NULL; } - ret = yyparse(&sb); + ret = tracefs_parse(&sb); yylex_destroy(sb.scanner); if (ret) From patchwork Tue Aug 3 17:05:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491240 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B44FFC432BE for ; Tue, 3 Aug 2021 17:06:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 95A3A60EB9 for ; Tue, 3 Aug 2021 17:06:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237639AbhHCRG0 (ORCPT ); Tue, 3 Aug 2021 13:06:26 -0400 Received: from mail.kernel.org ([198.145.29.99]:38746 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237521AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id DC41261107; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubq-QO; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 10/22] libtracefs: Add error message when match fields are not FROM and JOIN events Date: Tue, 3 Aug 2021 13:05:54 -0400 Message-Id: <20210803170606.694085-11-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" It is required that the "match" content (the ON portion of the SQL sequence) has a field from the FROM event and a field from the JOIN event. If they do not, then give a better message about what went wrong. To simplify addition of future errors, also add a parse_error() that calls into sql_parse_error() with the appropriate "ap" argument. That is, parse_error() takes a normal printf() form and then translates it to the vprintf from of sql_parse_error. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 2e301e024d13..da4668f53ea1 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include "tracefs.h" @@ -154,6 +155,16 @@ __hidden void sql_parse_error(struct sqlhist_bison *sb, const char *text, trace_seq_destroy(&s); } +static void parse_error(struct sqlhist_bison *sb, const char *text, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sql_parse_error(sb, text, fmt, ap); + va_end(ap); +} + static inline unsigned int quick_hash(const char *str) { unsigned int val = 0; @@ -647,6 +658,34 @@ static int update_vars(struct tep_handle *tep, return 0; } +static int match_error(struct sqlhist_bison *sb, struct match *match, + struct field *lmatch, struct field *rmatch) +{ + struct field *lval = &match->lval->field; + struct field *rval = &match->rval->field; + struct field *field; + struct expr *expr; + + if (lval->system != lmatch->system || + lval->event != lmatch->event) { + expr = match->lval; + field = lval; + } else { + expr = match->rval; + field = rval; + } + + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + parse_error(sb, field->raw, + "'%s' and '%s' must be a field for each event: '%s' and '%s'\n", + lval->raw, rval->raw, sb->table->to->field.raw, + sb->table->from->field.raw); + + return -1; +} + static int test_match(struct sql_table *table, struct match *match) { struct field *lval, *rval; @@ -678,13 +717,13 @@ static int test_match(struct sql_table *table, struct match *match) (rval->event != to->event) || (lval->system != from->system) || (lval->event != from->event)) - return -1; + return match_error(table->sb, match, from, to); } else { if ((rval->system != from->system) || (rval->event != from->event) || (lval->system != to->system) || (lval->event != to->event)) - return -1; + return match_error(table->sb, match, to, from); } return 0; } From patchwork Tue Aug 3 17:05:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491239 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 336B3C19F3F for ; Tue, 3 Aug 2021 17:06:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1537260EB9 for ; Tue, 3 Aug 2021 17:06:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237626AbhHCRG1 (ORCPT ); Tue, 3 Aug 2021 13:06:27 -0400 Received: from mail.kernel.org ([198.145.29.99]:38752 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237531AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id EFA196112E; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubt-RE; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 11/22] libtracefs: Add error message when match or init fails from bad events Date: Tue, 3 Aug 2021 13:05:55 -0400 Message-Id: <20210803170606.694085-12-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" If the tracefs_synth_init() or the matching fails due to events that do not exist, or if the match fields are not compatible with each other. Add an error message that reports this and where the problem is. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 98 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index da4668f53ea1..ab190d123800 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -507,6 +507,7 @@ __hidden int table_start(struct sqlhist_bison *sb) } static int test_event_exists(struct tep_handle *tep, + struct sqlhist_bison *sb, struct expr *expr, struct tep_event **pevent) { struct field *field = &expr->field; @@ -517,18 +518,30 @@ static int test_event_exists(struct tep_handle *tep, field->event = tep_find_event_by_name(tep, system, event); if (pevent) *pevent = field->event; - return field->event != NULL ? 0 : -1; + + if (field->event) + return 0; + + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + parse_error(sb, field->raw, "event not found\n"); + return -1; } -static int test_field_exists(struct expr *expr) +static int test_field_exists(struct tep_handle *tep, + struct sqlhist_bison *sb, + struct expr *expr) { struct field *field = &expr->field; struct tep_format_field *tfield; char *field_name; const char *p; - if (!field->event) - return -1; + if (!field->event) { + if (test_event_exists(tep, sb, expr, NULL)) + return -1; + } /* The field could have a conversion */ p = strchr(field->field, '.'); @@ -547,7 +560,16 @@ static int test_field_exists(struct expr *expr) tfield = tep_find_any_field(field->event, field_name); free(field_name); - return tfield != NULL ? 0 : -1; + if (tfield) + return 0; + + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + parse_error(sb, field->raw, + "Field '%s' not part of event %s\n", + field->field, field->event_name); + return -1; } static int update_vars(struct tep_handle *tep, @@ -585,7 +607,7 @@ static int update_vars(struct tep_handle *tep, if (!event_field->event_name) return -1; - if (test_event_exists(tep, expr, &event)) + if (test_event_exists(tep, sb, expr, &event)) return -1; if (!event_field->system) @@ -651,7 +673,7 @@ static int update_vars(struct tep_handle *tep, field->field = store_str(sb, TRACEFS_TIMESTAMP); if (!strcmp(field->field, "TIMESTAMP_USECS")) field->field = store_str(sb, TRACEFS_TIMESTAMP_USECS); - if (test_field_exists(expr)) + if (test_field_exists(tep, sb, expr)) return -1; } @@ -941,6 +963,62 @@ static int build_filter(struct tracefs_synth *synth, return ret; } +static void *field_match_error(struct tep_handle *tep, struct sqlhist_bison *sb, + struct match *match) +{ + switch (errno) { + case ENODEV: + case EBADE: + break; + default: + /* System error */ + return NULL; + } + + /* ENODEV means that an event or field does not exist */ + if (errno == ENODEV) { + if (test_field_exists(tep, sb, match->lval)) + return NULL; + if (test_field_exists(tep, sb, match->rval)) + return NULL; + return NULL; + } + + /* fields exist, but values are not compatible */ + sb->line_no = match->lval->line; + sb->line_idx = match->lval->idx; + + parse_error(sb, match->lval->field.raw, + "Field '%s' is not compatible to match field '%s'\n", + match->lval->field.raw, match->rval->field.raw); + return NULL; +} + +static void *synth_init_error(struct tep_handle *tep, struct sql_table *table) +{ + struct sqlhist_bison *sb = table->sb; + struct match *match = table->matches; + + switch (errno) { + case ENODEV: + case EBADE: + break; + default: + /* System error */ + return NULL; + } + + /* ENODEV could mean that start or end events do not exist */ + if (errno == ENODEV) { + if (test_event_exists(tep, sb, table->from, NULL)) + return NULL; + if (test_event_exists(tep, sb, table->to, NULL)) + return NULL; + } + + return field_match_error(tep, sb, match); +} + static struct tracefs_synth *build_synth(struct tep_handle *tep, const char *name, struct sql_table *table) @@ -991,7 +1069,7 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, start_event, end_system, end_event, start_match, end_match, NULL); if (!synth) - return NULL; + return synth_init_error(tep, table); for (match = match->next; match; match = match->next) { ret = test_match(table, match); @@ -1004,8 +1082,10 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, ret = tracefs_synth_add_match_field(synth, start_match, end_match, NULL); - if (ret < 0) + if (ret < 0) { + field_match_error(tep, table->sb, match); goto free; + } } for (expr = table->selections; expr; expr = expr->next) { From patchwork Tue Aug 3 17:05:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491235 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB0E5C4338F for ; Tue, 3 Aug 2021 17:06:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 953C361029 for ; Tue, 3 Aug 2021 17:06:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237851AbhHCRGr (ORCPT ); Tue, 3 Aug 2021 13:06:47 -0400 Received: from mail.kernel.org ([198.145.29.99]:38748 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237523AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id E832C61132; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002ubw-S7; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 12/22] libtracefs; Add error message for bad selections to SQL sequence Date: Tue, 3 Aug 2021 13:05:56 -0400 Message-Id: <20210803170606.694085-13-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" If the building of the synthetic event fails on creating the selection, report it properly. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index ab190d123800..041d7077c3eb 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -1019,6 +1019,16 @@ static void *synth_init_error(struct tep_handle *tep, struct sql_table *table) return field_match_error(tep, sb, match); } +static void selection_error(struct tep_handle *tep, + struct sqlhist_bison *sb, struct expr *expr) +{ + /* We just care about event not existing */ + if (errno != ENODEV) + return; + + test_field_exists(tep, sb, expr); +} + static struct tracefs_synth *build_synth(struct tep_handle *tep, const char *name, struct sql_table *table) @@ -1099,8 +1109,10 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, ret = tracefs_synth_add_end_field(synth, field->field, field->label); } - if (ret < 0) + if (ret < 0) { + selection_error(tep, table->sb, expr); goto free; + } continue; } From patchwork Tue Aug 3 17:05:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491234 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE805C19F34 for ; Tue, 3 Aug 2021 17:06:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DA35261029 for ; Tue, 3 Aug 2021 17:06:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237868AbhHCRGt (ORCPT ); Tue, 3 Aug 2021 13:06:49 -0400 Received: from mail.kernel.org ([198.145.29.99]:38756 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237537AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 0630461176; Tue, 3 Aug 2021 17:06:08 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002uc5-Uj; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 15/22] libtracefs: Add error message for bad filters in SQL statement Date: Tue, 3 Aug 2021 13:05:59 -0400 Message-Id: <20210803170606.694085-16-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" If a filter has a bad event, or incompatibility with the value assigned to it, have the error message display it. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 80 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index a0d934b4cd68..d7829d4804b1 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -879,14 +879,80 @@ static int verify_filter(struct sqlhist_bison *sb, struct filter *filter, } } -static int build_filter(struct tracefs_synth *synth, - bool start, struct filter *filter, bool *started) +static int test_field_exists(struct tep_handle *tep, struct sqlhist_bison *sb, + struct expr *expr); + +static void filter_compare_error(struct tep_handle *tep, + struct sqlhist_bison *sb, + struct expr *expr) +{ + struct field *field = &expr->field; + + switch (errno) { + case ENODEV: + case EBADE: + break; + case EINVAL: + parse_error(sb, field->raw, "Invalid compare\n"); + break; + default: + parse_error(sb, field->raw, "System error?\n"); + return; + } + + /* ENODEV means that an event or field does not exist */ + if (errno == ENODEV) { + if (test_field_exists(tep, sb, expr)) + return; + if (test_field_exists(tep, sb, expr)) + return; + return; + } + + /* fields exist, but values are not compatible */ + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + parse_error(sb, field->raw, + "Field '%s' is not compatible to be compared with the given value\n", + field->field); +} + +static void filter_error(struct tep_handle *tep, + struct sqlhist_bison *sb, struct expr *expr) +{ + struct filter *filter = &expr->filter; + + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + switch (filter->type) { + case FILTER_NOT_GROUP: + case FILTER_GROUP: + case FILTER_OR: + case FILTER_AND: + break; + default: + filter_compare_error(tep, sb, filter->lval); + return; + } + + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + parse_error(sb, "", "Problem with filter entry?\n"); +} + +static int build_filter(struct tep_handle *tep, struct sqlhist_bison *sb, + struct tracefs_synth *synth, + bool start, struct expr *expr, bool *started) { int (*append_filter)(struct tracefs_synth *synth, enum tracefs_filter type, const char *field, enum tracefs_compare compare, const char *val); + struct filter *filter = &expr->filter; enum tracefs_compare cmp; const char *val; int and_or = TRACEFS_FILTER_AND; @@ -916,7 +982,7 @@ static int build_filter(struct tracefs_synth *synth, NULL, 0, NULL); if (ret < 0) goto out; - ret = build_filter(synth, start, &filter->lval->filter, NULL); + ret = build_filter(tep, sb, synth, start, filter->lval, NULL); if (ret < 0) goto out; ret = append_filter(synth, TRACEFS_FILTER_CLOSE_PAREN, @@ -927,14 +993,14 @@ static int build_filter(struct tracefs_synth *synth, and_or = TRACEFS_FILTER_OR; /* Fall through */ case FILTER_AND: - ret = build_filter(synth, start, &filter->lval->filter, NULL); + ret = build_filter(tep, sb, synth, start, filter->lval, NULL); if (ret < 0) goto out; ret = append_filter(synth, and_or, NULL, 0, NULL); if (ret) goto out; - ret = build_filter(synth, start, &filter->rval->filter, NULL); + ret = build_filter(tep, sb, synth, start, filter->rval, NULL); goto out; default: break; @@ -968,6 +1034,8 @@ static int build_filter(struct tracefs_synth *synth, ret = append_filter(synth, TRACEFS_FILTER_COMPARE, filter->lval->field.field, cmp, val); + if (ret) + filter_error(tep, sb, expr); out: if (!ret && started) { if (*started) @@ -1193,7 +1261,7 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, else started = &started_end; - ret = build_filter(synth, start, &expr->filter, started); + ret = build_filter(tep, table->sb, synth, start, expr, started); if (ret < 0) goto free; } From patchwork Tue Aug 3 17:06:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491236 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 106A2C4320A for ; Tue, 3 Aug 2021 17:06:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F07FE61037 for ; Tue, 3 Aug 2021 17:06:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237606AbhHCRGq (ORCPT ); Tue, 3 Aug 2021 13:06:46 -0400 Received: from mail.kernel.org ([198.145.29.99]:38766 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237546AbhHCRGU (ORCPT ); Tue, 3 Aug 2021 13:06:20 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 0EFAB61183; Tue, 3 Aug 2021 17:06:09 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrj-002uc8-Vg; Tue, 03 Aug 2021 13:06:07 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH v3 16/22] libtracefs: Add error message when calculation has no label Date: Tue, 3 Aug 2021 13:06:00 -0400 Message-Id: <20210803170606.694085-17-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" If a calculation between event fields is performed and there's no label (name) for it, it errors out, causing the bison parser to give a strange error: FAILED MEMORY: add_selection(sb, (yyvsp[0].expr), NULL) Failed creating synthetic event!: No such file or directory Instead, just set the compare->name field to NULL, and report a better error later on in the processing. ERROR: 'no name' Field calculations must be labeled 'AS name' Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index d7829d4804b1..81a0cd1a908b 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -243,8 +243,6 @@ __hidden int add_selection(struct sqlhist_bison *sb, void *select, case EXPR_FIELD: break; case EXPR_COMPARE: - if (!name) - return -1; expr->compare.name = name; break; case EXPR_NUMBER: @@ -779,6 +777,9 @@ static int build_compare(struct tracefs_synth *synth, enum tracefs_synth_calc calc; int ret; + if (!compare->name) + return -1; + lval = &compare->lval->field; rval = &compare->rval->field; @@ -1117,6 +1118,14 @@ static void compare_error(struct tep_handle *tep, { struct compare *compare = &expr->compare; + if (!compare->name) { + sb->line_no = expr->line; + sb->line_idx = expr->idx + strlen("no name"); + + parse_error(sb, "no name", + "Field calculations must be labeled 'AS name'\n"); + } + switch (errno) { case ENODEV: case EBADE: From patchwork Tue Aug 3 17:06:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491238 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD49FC4320A for ; Tue, 3 Aug 2021 17:06:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 90F9E610FC for ; Tue, 3 Aug 2021 17:06:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237694AbhHCRG3 (ORCPT ); Tue, 3 Aug 2021 13:06:29 -0400 Received: from mail.kernel.org ([198.145.29.99]:38746 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237564AbhHCRGV (ORCPT ); Tue, 3 Aug 2021 13:06:21 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 2699E611ED; Tue, 3 Aug 2021 17:06:09 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAxrk-002ucH-2F; Tue, 03 Aug 2021 13:06:08 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" , "Ahmed S . Darwish" Subject: [PATCH v3 19/22] libtracefs: Allow for simple SQL statements to create a histogram Date: Tue, 3 Aug 2021 13:06:03 -0400 Message-Id: <20210803170606.694085-20-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803170606.694085-1-rostedt@goodmis.org> References: <20210803170606.694085-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Allow tracefs_sql() to take a simple select statement without the JOIN .. ON clause, that will simply update the start event. This, along with tracefs_synth_get_start_hist(), will allow a user to utilize tracefs_sql() to create a synthetic event. Link: https://lore.kernel.org/linux-rt-users/YQakDYRnId+bK+ue@lx-t490/ Suggested-by: Ahmed S. Darwish Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-sql.txt | 27 +++++- include/tracefs-local.h | 3 + src/sqlhist.y | 11 ++- src/tracefs-hist.c | 60 +++++++++---- src/tracefs-sqlhist.c | 144 +++++++++++++++++++++++++++++-- 5 files changed, 216 insertions(+), 29 deletions(-) diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt index e10a22cd531b..ee8d5c1d63c7 100644 --- a/Documentation/libtracefs-sql.txt +++ b/Documentation/libtracefs-sql.txt @@ -32,6 +32,8 @@ to attach two events together and form another event (table). Utilizing the SQL *SELECT* *FROM* *JOIN* *ON* [ *WHERE* ] syntax, a synthetic event can easily be created from two different events. +For simple SQL queries to make a histogram instead of a synthetic event, see +HISTOGRAMS below. *tracefs_sql*() takes in a *tep* handler (See _tep_local_events_(3)) that is used to verify the events within the _sql_buffer_ expression. The _name_ is the name of the @@ -160,6 +162,12 @@ select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sche WHERE start.prio < 100 || end.prev_prio < 100 -- +HISTOGRAMS +---------- + +Simple SQL statements without the *JOIN* *ON* may also be used, which will create a histogram +instead. When doing this, the struct tracefs_hist descriptor can be retrieved from the +returned synthetic event descriptor via the *tracefs_synth_get_start_hist*(3). RETURN VALUE ------------ @@ -243,9 +251,22 @@ static int do_sql(const char *buffer, const char *name, exit(-1); } - tracefs_synth_show(&seq, NULL, synth); - if (execute) - tracefs_synth_create(NULL, synth); + if (tracefs_synth_complete(synth)) { + tracefs_synth_show(&seq, NULL, synth); + if (execute) + tracefs_synth_create(NULL, synth); + } else { + struct tracefs_hist *hist; + hist = tracefs_synth_get_start_hist(synth); + if (!hist) { + perror("get_start_hist"); + exit(-1); + } + tracefs_hist_show(&seq, NULL, hist, 0); + if (execute) + tracefs_hist_start(NULL, hist); + } + tracefs_synth_free(synth); trace_seq_do_printf(&seq); diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 41fbcc0faa95..09288aeac521 100644 --- a/include/tracefs-local.h +++ b/include/tracefs-local.h @@ -85,4 +85,7 @@ int trace_append_filter(char **filter, unsigned int *state, enum tracefs_compare compare, const char *val); +struct tracefs_synth *synth_init_from(struct tep_handle *tep, + const char *start_system, + const char *start_event); #endif /* _TRACE_FS_LOCAL_H */ diff --git a/src/sqlhist.y b/src/sqlhist.y index 9d03a457ae84..d5cbecc7bf92 100644 --- a/src/sqlhist.y +++ b/src/sqlhist.y @@ -63,7 +63,7 @@ extern void yyerror(struct sqlhist_bison *, char *fmt, ...); %type name label -%type selection_expr field item named_field join_clause +%type selection_expr field item named_field %type selection_addition %type compare compare_list compare_cmds compare_items %type compare_and_or @@ -202,8 +202,13 @@ opt_where_clause : | where_clause ; +opt_join_clause : + /* empty set */ + | join_clause + ; + table_exp : - from_clause join_clause opt_where_clause + from_clause opt_join_clause opt_where_clause ; from_clause : @@ -222,7 +227,7 @@ from_clause : ; join_clause : - JOIN item ON match_clause { add_to(sb, $2); } + JOIN item ON match_clause { add_to(sb, $2); } ; match : diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index 305e3e720341..301abc255d5f 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -724,6 +724,33 @@ static int add_var(char ***list, const char *name, const char *var, bool is_var) return 0; } +__hidden struct tracefs_synth * +synth_init_from(struct tep_handle *tep, const char *start_system, + const char *start_event_name) +{ + struct tep_event *start_event; + struct tracefs_synth *synth; + + start_event = tep_find_event_by_name(tep, start_system, + start_event_name); + if (!start_event) { + errno = ENODEV; + return NULL; + } + + synth = calloc(1, sizeof(*synth)); + if (!synth) + return NULL; + + synth->start_event = start_event; + + /* Hold onto a reference to this handler */ + tep_ref(tep); + synth->tep = tep; + + return synth; +} + /** * tracefs_synth_init - create a new tracefs_synth instance * @tep: The tep handle that holds the events to work on @@ -778,7 +805,6 @@ struct tracefs_synth *tracefs_synth_init(struct tep_handle *tep, const char *end_match_field, const char *match_name) { - struct tep_event *start_event; struct tep_event *end_event; struct tracefs_synth *synth; int ret = 0; @@ -789,25 +815,18 @@ struct tracefs_synth *tracefs_synth_init(struct tep_handle *tep, return NULL; } - start_event = tep_find_event_by_name(tep, start_system, - start_event_name); - if (!start_event) { - errno = ENODEV; + synth = synth_init_from(tep, start_system, start_event_name); + if (!synth) return NULL; - } end_event = tep_find_event_by_name(tep, end_system, end_event_name); if (!end_event) { + tep_unref(tep); errno = ENODEV; return NULL; } - synth = calloc(1, sizeof(*synth)); - if (!synth) - return NULL; - - synth->start_event = start_event; synth->end_event = end_event; synth->name = strdup(name); @@ -815,10 +834,6 @@ struct tracefs_synth *tracefs_synth_init(struct tep_handle *tep, ret = tracefs_synth_add_match_field(synth, start_match_field, end_match_field, match_name); - /* Hold onto a reference to this handler */ - tep_ref(tep); - synth->tep = tep; - if (!synth->name || !synth->start_keys || !synth->end_keys || ret) { tracefs_synth_free(synth); synth = NULL; @@ -1458,6 +1473,11 @@ int tracefs_synth_create(struct tracefs_instance *instance, return -1; } + if (!synth->name || !synth->end_event) { + errno = EUNATCH; + return -1; + } + if (verify_state(synth) < 0) return -1; @@ -1540,6 +1560,11 @@ int tracefs_synth_destroy(struct tracefs_instance *instance, return -1; } + if (!synth->name || !synth->end_event) { + errno = EUNATCH; + return -1; + } + /* Try to disable the event if possible */ tracefs_event_disable(instance, "synthetic", synth->name); @@ -1596,6 +1621,11 @@ int tracefs_synth_show(struct trace_seq *seq, return -1; } + if (!synth->name || !synth->end_event) { + errno = EUNATCH; + return -1; + } + synthetic_event = create_synthetic_event(synth); if (!synthetic_event) return -1; diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 81a0cd1a908b..d9ebe2eab411 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -678,6 +678,70 @@ static int update_vars(struct tep_handle *tep, return 0; } +/* + * Called when there's a FROM but no JOIN(to), which means that the + * selections can be fields and not mention the event itself. + */ +static int update_fields(struct tep_handle *tep, + struct sql_table *table, + struct expr *expr) +{ + struct field *event_field = &expr->field; + struct sqlhist_bison *sb = table->sb; + struct tep_format_field *tfield; + struct tep_event *event; + struct field *field; + const char *p; + int len; + + /* First update fields with aliases an such and add event */ + update_vars(tep, table, expr); + + /* + * If event is not found, the creation of the synth will + * add a proper error, so return "success". + */ + if (!event_field->event) + return 0; + + event = event_field->event; + + for_each_field(expr, field, table) { + const char *field_name; + + field = &expr->field; + + if (field->event) + continue; + + field_name = field->raw; + + p = strchr(field_name, '.'); + if (p) { + len = p - field_name; + p = strndup(field_name, len); + if (!p) + return -1; + field_name = store_str(sb, p); + if (!field_name) + return -1; + free((char *)p); + } + + tfield = tep_find_any_field(event, field_name); + /* Let it error properly later */ + if (!tfield) + continue; + + field->system = event_field->system; + field->event_name = event_field->event_name; + field->event = event; + field->field = field_name; + } + + return 0; +} + static int match_error(struct sqlhist_bison *sb, struct match *match, struct field *lmatch, struct field *rmatch) { @@ -1153,6 +1217,42 @@ static void compare_error(struct tep_handle *tep, compare->lval->field.raw, compare->rval->field.raw); } +static void compare_no_to_error(struct sqlhist_bison *sb, struct expr *expr) +{ + struct compare *compare = &expr->compare; + + sb->line_no = compare->lval->line; + sb->line_idx = compare->lval->idx; + + parse_error(sb, compare->lval->field.raw, + "Simple SQL (without JOIN/ON) do not allow comparisons\n", + compare->lval->field.raw, compare->rval->field.raw); +} + +static void where_no_to_error(struct sqlhist_bison *sb, struct expr *expr, + const char *from_event, const char *event) +{ + while (expr) { + switch (expr->filter.type) { + case FILTER_OR: + case FILTER_AND: + case FILTER_GROUP: + case FILTER_NOT_GROUP: + expr = expr->filter.lval; + continue; + default: + break; + } + break; + } + sb->line_no = expr->filter.lval->line; + sb->line_idx = expr->filter.lval->idx; + + parse_error(sb, expr->filter.lval->field.raw, + "Event '%s' does not match FROM event '%s'\n", + event, from_event); +} + static struct tracefs_synth *build_synth(struct tep_handle *tep, const char *name, struct sql_table *table) @@ -1171,17 +1271,35 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, bool started_end = false; int ret; - if (!table->to || !table->from) + if (!table->from) return NULL; - ret = update_vars(tep, table, table->to); + /* This could be a simple SQL statement to only build a histogram */ + if (!table->to) { + ret = update_fields(tep, table, table->from); + if (ret < 0) + return NULL; + + start_system = table->from->field.system; + start_event = table->from->field.event_name; + + synth = synth_init_from(tep, start_system, start_event); + if (!synth) + return synth_init_error(tep, table); + goto hist_only; + } + + ret = update_vars(tep, table, table->from); if (ret < 0) return NULL; - ret = update_vars(tep, table, table->from); + ret = update_vars(tep, table, table->to); if (ret < 0) return NULL; + start_system = table->from->field.system; + start_event = table->from->field.event_name; + match = table->matches; if (!match) return NULL; @@ -1190,9 +1308,6 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, if (ret < 0) return NULL; - start_system = table->from->field.system; - start_event = table->from->field.event_name; - end_system = table->to->field.system; end_event = table->to->field.event_name; @@ -1222,14 +1337,18 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, } } + hist_only: + /* table->to may be NULL here */ + for (expr = table->selections; expr; expr = expr->next) { if (expr->type == EXPR_FIELD) { + ret = -1; field = &expr->field; if (field->system == start_system && field->event_name == start_event) { ret = tracefs_synth_add_start_field(synth, field->field, field->label); - } else { + } else if (table->to) { ret = tracefs_synth_add_end_field(synth, field->field, field->label); } @@ -1240,6 +1359,11 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, continue; } + if (!table->to) { + compare_no_to_error(table->sb, expr); + goto free; + } + if (expr->type != EXPR_COMPARE) goto free; @@ -1267,7 +1391,11 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, if (start) started = &started_start; - else + else if (!table->to) { + where_no_to_error(table->sb, expr, start_event, + filter_event); + goto free; + } else started = &started_end; ret = build_filter(tep, table->sb, synth, start, expr, started);