From patchwork Tue Aug 3 04:23:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491247 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 AD92FC4320E for ; Tue, 3 Aug 2021 04:24:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9B8BB61159 for ; Tue, 3 Aug 2021 04:24:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234063AbhHCEYu (ORCPT ); Tue, 3 Aug 2021 00:24:50 -0400 Received: from mail.kernel.org ([198.145.29.99]:57204 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233681AbhHCEYI (ORCPT ); Tue, 3 Aug 2021 00:24:08 -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 E385B61051; Tue, 3 Aug 2021 04:23:56 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly7-002qn3-Lb; Tue, 03 Aug 2021 00:23:55 -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 v2 01/21] libtracefs: Added new API tracefs_sql() Date: Tue, 3 Aug 2021 00:23:27 -0400 Message-Id: <20210803042347.679499-2-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 | 691 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1007 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..7ec0c11b902e --- /dev/null +++ b/src/tracefs-sqlhist.c @@ -0,0 +1,691 @@ +// 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; + 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 update_vars(struct sql_table *table, struct field *event) +{ + struct sqlhist_bison *sb = table->sb; + struct expr *expr; + struct field *field; + const char *label; + const char *p, *r; + char *system; + int len; + + p = strchr(event->raw, '.'); + if (p) { + system = strndup(event->raw, p - event->raw); + if (!system) + return -1; + event->system = store_str(sb, system); + free(system); + if (!event->system) + return -1; + p++; + } else { + p = event->raw; + } + + event->event = store_str(sb, p); + if (!event->event) + return -1; + + if (!event->label) + event->label = event->event; + + label = event->label; + len = strlen(label); + + for_each_field(expr, field, table) { + field = &expr->field; + + if (field->event) + continue; + + p = strchr(field->raw, '.'); + if (p) { + /* Does this field have a system */ + r = strchr(p + 1, '.'); + if (r) { + /* This has a system, and is not a alias */ + system = strndup(field->raw, p - field->raw); + if (!system) + return -1; + field->system = store_str(sb, system); + free(system); + if (!field->system) + return -1; + + /* save the event as well */ + p++; + system = strndup(p, r - p); + if (!system) + return -1; + field->event = store_str(sb, system); + free(system); + if (!field->event) + return -1; + r++; + field->field = store_str(sb, r); + goto check_timestamps; + } + } + + if (strncmp(field->raw, label, len)) + continue; + + if (field->raw[len] != '.') + continue; + + field->system = event->system; + field->event = event->event; + field->field = field->raw + len + 1; + check_timestamps: + if (!strcmp(field->field, "TIMESTAMP")) + field->field = store_str(sb, TRACEFS_TIMESTAMP); + else if (!strcmp(field->field, "TIMESTAMP_USECS")) + field->field = store_str(sb, TRACEFS_TIMESTAMP_USECS); + } + + 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 == 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(table, &table->to->field); + if (ret < 0) + return NULL; + + ret = update_vars(table, &table->from->field); + 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; + + end_system = table->to->field.system; + end_event = table->to->field.event; + + 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 == 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 04:23:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491254 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 E9BF3C432BE for ; Tue, 3 Aug 2021 04:23:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C65CB61100 for ; Tue, 3 Aug 2021 04:23:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233658AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -0400 Received: from mail.kernel.org ([198.145.29.99]:57036 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229611AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 DA6FA60F92; Tue, 3 Aug 2021 04:23:56 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly7-002qn5-My; Tue, 03 Aug 2021 00:23:55 -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 v2 02/21] tracefs: Add unit tests for tracefs_sql() Date: Tue, 3 Aug 2021 00:23:28 -0400 Message-Id: <20210803042347.679499-3-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 04:23:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491253 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 2781AC4338F for ; Tue, 3 Aug 2021 04:24:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0019561159 for ; Tue, 3 Aug 2021 04:24:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233752AbhHCEYJ (ORCPT ); Tue, 3 Aug 2021 00:24:09 -0400 Received: from mail.kernel.org ([198.145.29.99]:57112 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231966AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 DD32D6104F; Tue, 3 Aug 2021 04:23:56 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly7-002qn7-Nw; Tue, 03 Aug 2021 00:23:55 -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 v2 03/21] libtracefs: Add comparing start and end fields in tracefs_sql() Date: Tue, 3 Aug 2021 00:23:29 -0400 Message-Id: <20210803042347.679499-4-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 7ec0c11b902e..cf2661773679 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -42,17 +42,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 { @@ -61,6 +76,8 @@ struct expr { enum expr_type type; union { struct field field; + struct filter filter; + struct compare compare; const char *string; long number; }; @@ -209,8 +226,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; } @@ -277,8 +300,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; @@ -292,6 +317,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) { @@ -331,6 +359,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) { @@ -522,6 +565,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 == 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) @@ -602,7 +678,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 04:23:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491251 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 6FAA0C4320A for ; Tue, 3 Aug 2021 04:24:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 57A1C61158 for ; Tue, 3 Aug 2021 04:24:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233821AbhHCEYU (ORCPT ); Tue, 3 Aug 2021 00:24:20 -0400 Received: from mail.kernel.org ([198.145.29.99]:57166 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232839AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 F10B9610A8; Tue, 3 Aug 2021 04:23:56 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly7-002qnI-R5; Tue, 03 Aug 2021 00:23:55 -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 v2 06/21] libtracefs: Add unit test to test tracefs_sql() where clause Date: Tue, 3 Aug 2021 00:23:32 -0400 Message-Id: <20210803042347.679499-7-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 filtering of events via the WHERE clause. Signed-off-by: Steven Rostedt (VMware) --- utest/tracefs-utest.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index f4e1a6b90a46..645c84c31f0e 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -53,6 +53,13 @@ #define SQL_3_EVENT "wakeup_lat" #define SQL_3_SQL "select start.pid, end.next_prio as prio, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start join sched_switch as end on start.pid = end.next_pid" +#define SQL_4_EVENT "wakeup_lat_2" +#define SQL_4_SQL "select start.pid, end.next_prio as prio, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start join sched_switch as end on start.pid = end.next_pid where (start.prio >= 1 && start.prio < 100) || !(start.pid >= 0 && start.pid <= 1) && end.prev_pid != 0" + +#define SQL_5_EVENT "irq_lat" +#define SQL_5_SQL "select end.common_pid as pid, (end.common_timestamp.usecs - start.common_timestamp.usecs) as irq_lat from irq_disable as start join irq_enable as end on start.common_pid = end.common_pid, start.parent_offs == end.parent_offs where start.common_pid != 0" +#define SQL_5_START "irq_disable" + static struct tracefs_instance *test_instance; static struct tep_handle *test_tep; struct test_sample { @@ -336,6 +343,7 @@ static void test_instance_trace_sql(struct tracefs_instance *instance) struct tracefs_synth *synth; struct trace_seq seq; struct tep_handle *tep; + struct tep_event *event; int ret; tep = tracefs_local_events(NULL); @@ -364,6 +372,23 @@ static void test_instance_trace_sql(struct tracefs_instance *instance) tracefs_synth_free(synth); trace_seq_reset(&seq); + synth = tracefs_sql(tep, SQL_4_EVENT, SQL_4_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); + + event = tep_find_event_by_name(tep, NULL, SQL_5_START); + if (event) { + synth = tracefs_sql(tep, SQL_5_EVENT, SQL_5_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 04:23:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491252 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 25814C4320E for ; Tue, 3 Aug 2021 04:24:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0F09861168 for ; Tue, 3 Aug 2021 04:24:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233797AbhHCEYP (ORCPT ); Tue, 3 Aug 2021 00:24:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:57148 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232667AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 ED468610A0; Tue, 3 Aug 2021 04:23:56 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly7-002qnO-Sq; Tue, 03 Aug 2021 00:23:55 -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 v2 08/21] libtracefs: Make parser unique to libtracefs Date: Tue, 3 Aug 2021 00:23:34 -0400 Message-Id: <20210803042347.679499-9-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 e8f77d60659f..933b3609733b 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -1021,7 +1021,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 04:23:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491250 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 953F6C4320A for ; Tue, 3 Aug 2021 04:24:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7DD1E6115C for ; Tue, 3 Aug 2021 04:24:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233913AbhHCEYY (ORCPT ); Tue, 3 Aug 2021 00:24:24 -0400 Received: from mail.kernel.org ([198.145.29.99]:57180 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233546AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 0ACC9610FB; Tue, 3 Aug 2021 04:23:56 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly7-002qnR-Tg; Tue, 03 Aug 2021 00:23:55 -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 v2 09/21] libtracefs: Add line number and index to expr structure Date: Tue, 3 Aug 2021 00:23:35 -0400 Message-Id: <20210803042347.679499-10-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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)" In order to have better error messages, record the line number and index when an expr structure is created. Then this can be used to show where in the SQL sequence a problem was found if the building of the synth event has issues. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 933b3609733b..887c2441a39e 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -72,6 +72,8 @@ struct expr { struct expr *free_list; struct expr *next; enum expr_type type; + int line; + int idx; union { struct field field; struct filter filter; @@ -300,6 +302,8 @@ static void *create_expr(struct sqlhist_bison *sb, sb->table->exprs = expr; expr->type = type; + expr->line = sb->line_no; + expr->idx = sb->line_idx; switch (type) { case EXPR_FIELD: return &expr->field; From patchwork Tue Aug 3 04:23:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491249 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 B2129C4320E for ; Tue, 3 Aug 2021 04:24:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9B78461159 for ; Tue, 3 Aug 2021 04:24:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233981AbhHCEYh (ORCPT ); Tue, 3 Aug 2021 00:24:37 -0400 Received: from mail.kernel.org ([198.145.29.99]:57226 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233715AbhHCEYI (ORCPT ); Tue, 3 Aug 2021 00:24:08 -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 215226112E; Tue, 3 Aug 2021 04:23:57 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly8-002qng-1t; Tue, 03 Aug 2021 00:23:56 -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 v2 14/21] libtracefs: Add error message for grouping events in SQL filter Date: Tue, 3 Aug 2021 00:23:40 -0400 Message-Id: <20210803042347.679499-15-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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)" One requirement for the SQL filter in tracefs_sql() is that the WHERE clause (filter) can only filter the FROM and JOIN events with "&&". That is, you can not have: sched_switch.next_pid == 0 || sched_waking.pid == 0 As the filtering one event stops the synthetic event, having an || conjunction makes no sense. Add an error message that explains this when it is found. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-sqlhist.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index ff0869232a9e..1767c33d77d0 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -715,21 +715,36 @@ static int build_compare(struct tracefs_synth *synth, return ret; } -static int do_verify_filter(struct filter *filter, +static int verify_filter_error(struct sqlhist_bison *sb, struct expr *expr, + const char *event) +{ + struct field *field = &expr->field; + + sb->line_no = expr->line; + sb->line_idx = expr->idx; + + parse_error(sb, field->raw, + "event '%s' can not be grouped or '||' together with '%s'\n" + "All filters between '&&' must be for the same event\n", + field->event, event); + return -1; +} + +static int do_verify_filter(struct sqlhist_bison *sb, struct filter *filter, const char **system, const char **event) { int ret; if (filter->type == FILTER_OR || filter->type == FILTER_AND) { - ret = do_verify_filter(&filter->lval->filter, system, event); + ret = do_verify_filter(sb, &filter->lval->filter, system, event); if (ret) return ret; - return do_verify_filter(&filter->rval->filter, system, event); + return do_verify_filter(sb, &filter->rval->filter, system, event); } if (filter->type == FILTER_GROUP || filter->type == FILTER_NOT_GROUP) { - return do_verify_filter(&filter->lval->filter, system, event); + return do_verify_filter(sb, &filter->lval->filter, system, event); } /* @@ -744,12 +759,12 @@ static int do_verify_filter(struct filter *filter, if (filter->lval->field.system != *system || filter->lval->field.event != *event) - return -1; + return verify_filter_error(sb, filter->lval, *event); return 0; } -static int verify_filter(struct filter *filter, +static int verify_filter(struct sqlhist_bison *sb, struct filter *filter, const char **system, const char **event) { int ret; @@ -761,17 +776,17 @@ static int verify_filter(struct filter *filter, case FILTER_NOT_GROUP: break; default: - return do_verify_filter(filter, system, event); + return do_verify_filter(sb, filter, system, event); } - ret = do_verify_filter(&filter->lval->filter, system, event); + ret = do_verify_filter(sb, &filter->lval->filter, system, event); if (ret) return ret; switch (filter->type) { case FILTER_OR: case FILTER_AND: - return do_verify_filter(&filter->rval->filter, system, event); + return do_verify_filter(sb, &filter->rval->filter, system, event); default: return 0; } @@ -1117,7 +1132,7 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, bool *started; bool start; - ret = verify_filter(&expr->filter, &filter_system, + ret = verify_filter(table->sb, &expr->filter, &filter_system, &filter_event); if (ret < 0) goto free; From patchwork Tue Aug 3 04:23:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491245 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 71C90C4338F for ; Tue, 3 Aug 2021 04:25:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5B3ED61155 for ; Tue, 3 Aug 2021 04:25:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234172AbhHCEZF (ORCPT ); Tue, 3 Aug 2021 00:25:05 -0400 Received: from mail.kernel.org ([198.145.29.99]:57200 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233650AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 219376112F; Tue, 3 Aug 2021 04:23:57 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly8-002qnj-2j; Tue, 03 Aug 2021 00:23:56 -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 v2 15/21] libtracefs: Add error message for bad filters in SQL statement Date: Tue, 3 Aug 2021 00:23:41 -0400 Message-Id: <20210803042347.679499-16-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 1767c33d77d0..f191661610c9 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -792,14 +792,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; @@ -829,7 +895,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, @@ -840,14 +906,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; @@ -881,6 +947,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) @@ -1145,7 +1213,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 04:23:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491244 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 77C65C432BE for ; Tue, 3 Aug 2021 04:25:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 57E1261164 for ; Tue, 3 Aug 2021 04:25:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233642AbhHCEZM (ORCPT ); Tue, 3 Aug 2021 00:25:12 -0400 Received: from mail.kernel.org ([198.145.29.99]:57190 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233627AbhHCEYH (ORCPT ); Tue, 3 Aug 2021 00:24:07 -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 1DB366112D; Tue, 3 Aug 2021 04:23:57 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly8-002qnm-3c; Tue, 03 Aug 2021 00:23:56 -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 v2 16/21] libtracefs: Add error message when calculation has no label Date: Tue, 3 Aug 2021 00:23:42 -0400 Message-Id: <20210803042347.679499-17-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 f191661610c9..c27f7478a527 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -242,8 +242,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: @@ -692,6 +690,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; @@ -1069,6 +1070,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 04:23:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 491246 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 A99DAC432BE for ; Tue, 3 Aug 2021 04:24:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9188561158 for ; Tue, 3 Aug 2021 04:24:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234115AbhHCEY4 (ORCPT ); Tue, 3 Aug 2021 00:24:56 -0400 Received: from mail.kernel.org ([198.145.29.99]:57244 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233726AbhHCEYI (ORCPT ); Tue, 3 Aug 2021 00:24:08 -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 40D2461167; Tue, 3 Aug 2021 04:23:57 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly8-002qns-5i; Tue, 03 Aug 2021 00:23:56 -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 v2 18/21] libtracefs: Allow for simple SQL statements to create a histogram Date: Tue, 3 Aug 2021 00:23:44 -0400 Message-Id: <20210803042347.679499-19-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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 | 141 +++++++++++++++++++++++++++++-- 5 files changed, 212 insertions(+), 30 deletions(-) diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt index 242e348a5bbf..190abe641d7c 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 0605e1fe600e..f6f7149b07d4 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; @@ -1457,6 +1472,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; @@ -1539,6 +1559,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); @@ -1595,6 +1620,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 c27f7478a527..c4514409645c 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -591,6 +591,69 @@ static int update_vars(struct sql_table *table, struct field *event) 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 field *event_field) +{ + struct sqlhist_bison *sb = table->sb; + struct tep_format_field *tfield; + struct tep_event *event; + struct expr *expr; + struct field *field; + const char *p; + int len; + + /* First update fields with aliases an such */ + update_vars(table, event_field); + + /* The update_vars already updated event->system and event->event */ + event = tep_find_event_by_name(tep, event_field->system, + event_field->event); + /* + * If event is not found, the creation of the synth will + * add a proper error, so return "success". + */ + if (!event) + return 0; + + 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 = event_field->event; + field->field = field_name; + } + + return 0; +} + static int match_error(struct sqlhist_bison *sb, struct match *match, struct field *lmatch, struct field *rmatch) { @@ -1105,6 +1168,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) @@ -1123,17 +1222,31 @@ 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(table, &table->to->field); - if (ret < 0) - return NULL; + /* This could be a simple SQL statement to only build a histogram */ + if (!table->to) { + ret = update_fields(tep, table, &table->from->field); + if (ret < 0) + return NULL; + + start_system = table->from->field.system; + start_event = table->from->field.event; + + synth = synth_init_from(tep, start_system, start_event); + if (!synth) + return synth_init_error(tep, table); + goto hist_only; + } ret = update_vars(table, &table->from->field); if (ret < 0) return NULL; + start_system = table->from->field.system; + start_event = table->from->field.event; + match = table->matches; if (!match) return NULL; @@ -1142,9 +1255,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; - end_system = table->to->field.system; end_event = table->to->field.event; @@ -1174,14 +1284,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 == 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); } @@ -1192,6 +1306,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; @@ -1219,7 +1338,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); From patchwork Tue Aug 3 04:23: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: 491248 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 F1379C4320A for ; Tue, 3 Aug 2021 04:24:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DD9E261159 for ; Tue, 3 Aug 2021 04:24:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234027AbhHCEYl (ORCPT ); Tue, 3 Aug 2021 00:24:41 -0400 Received: from mail.kernel.org ([198.145.29.99]:57184 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233720AbhHCEYI (ORCPT ); Tue, 3 Aug 2021 00:24:08 -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 52202611CC; Tue, 3 Aug 2021 04:23:57 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mAly8-002qo1-8x; Tue, 03 Aug 2021 00:23:56 -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 v2 21/21] libtracefs: Add CAST(x AS _COUNTER_) syntax to create values in histograms Date: Tue, 3 Aug 2021 00:23:47 -0400 Message-Id: <20210803042347.679499-22-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210803042347.679499-1-rostedt@goodmis.org> References: <20210803042347.679499-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)" Use the CAST() command of SQL to define which items in the select should be cast as values and not keys. By casting the field as the special value _COUNTER_, it will turn the selection item into a value. For example: SELECT common_pid, CAST(bytes_req AS _COUNTER_) FROM kmalloc Will create: echo 'hist:keys=common_pid:vals=bytes_req' > events/kmem/kmalloc/trigger Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-sql.txt | 24 ++++++++++++++++++++++++ include/tracefs-local.h | 2 ++ include/tracefs.h | 3 +++ src/tracefs-hist.c | 28 ++++++++++++++++++++++++++-- src/tracefs-sqlhist.c | 23 +++++++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt index 314f607fa84e..7b616fa27d23 100644 --- a/Documentation/libtracefs-sql.txt +++ b/Documentation/libtracefs-sql.txt @@ -238,6 +238,30 @@ name of the process. *LOG* or *LOG2* - bucket the key values in a log 2 values (1, 2, 3-4, 5-8, 9-16, 17-32, ...) +The above fields are not case sensitive, and "LOG2" works as good as "log". + +A special CAST to _COUNTER_ or __COUNTER__ will make the field a value and not +a key. For example: + +[source,c] +-- + SELECT common_pid, CAST(bytes_req AS _COUNTER_) FROM kmalloc +-- + +Which will create + +[source,c] +-- + echo 'hist:keys=common_pid:vals=bytes_req' > events/kmem/kmalloc/trigger + + cat events/kmem/kmalloc/hist + +{ common_pid: 1812 } hitcount: 1 bytes_req: 32 +{ common_pid: 9111 } hitcount: 2 bytes_req: 272 +{ common_pid: 1768 } hitcount: 3 bytes_req: 1112 +{ common_pid: 0 } hitcount: 4 bytes_req: 512 +{ common_pid: 18297 } hitcount: 11 bytes_req: 2004 +-- RETURN VALUE ------------ diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 07d40b2fae4f..684eccffafee 100644 --- a/include/tracefs-local.h +++ b/include/tracefs-local.h @@ -88,6 +88,8 @@ int trace_append_filter(char **filter, unsigned int *state, struct tracefs_synth *synth_init_from(struct tep_handle *tep, const char *start_system, const char *start_event); + +#define HIST_COUNTER_TYPE (TRACEFS_HIST_KEY_MAX + 100) int synth_add_start_field(struct tracefs_synth *synth, const char *start_field, const char *name, diff --git a/include/tracefs.h b/include/tracefs.h index 219adba4b0ce..17020de0108a 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -264,6 +264,7 @@ enum tracefs_hist_key_type { TRACEFS_HIST_KEY_EXECNAME, TRACEFS_HIST_KEY_LOG, TRACEFS_HIST_KEY_USECS, + TRACEFS_HIST_KEY_MAX }; enum tracefs_hist_sort_direction { @@ -275,6 +276,8 @@ enum tracefs_hist_sort_direction { #define TRACEFS_HIST_TIMESTAMP_USECS "common_timestamp.usecs" #define TRACEFS_HIST_CPU "cpu" +#define TRACEFS_HIST_COUNTER "__COUNTER__" + #define TRACEFS_HIST_HITCOUNT "hitcount" struct tracefs_hist; diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index d62422399552..c3aecf9a8fef 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -256,7 +256,7 @@ int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, bool use_key = false; char *key_type = NULL; char **new_list; - int ret; + int ret = -1; switch (type) { case TRACEFS_HIST_KEY_NORMAL: @@ -284,6 +284,9 @@ int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, case TRACEFS_HIST_KEY_USECS: ret = asprintf(&key_type, "%s.usecs", key); break; + case TRACEFS_HIST_KEY_MAX: + /* error */ + break; } if (ret < 0) @@ -1450,6 +1453,9 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) for (i = 0; keys[i]; i++) { int type = types ? types[i] : 0; + if (type == HIST_COUNTER_TYPE) + continue; + key = keys[i]; if (i) { @@ -1466,7 +1472,25 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) } } - if (hist && synth->start_filter) { + if (!hist) + return NULL; + + for (i = 0; keys[i]; i++) { + int type = types ? types[i] : 0; + + if (type != HIST_COUNTER_TYPE) + continue; + + key = keys[i]; + + ret = tracefs_hist_add_value(hist, key); + if (ret < 0) { + tracefs_hist_free(hist); + return NULL; + } + } + + if (synth->start_filter) { hist->filter = strdup(synth->start_filter); if (!hist->filter) { tracefs_hist_free(hist); diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 88563e98f298..1a3cf37c84ba 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -1253,6 +1253,17 @@ static int verify_field_type(struct tep_handle *tep, if (!type) return -1; + if (!strcmp(type, TRACEFS_HIST_COUNTER) || + !strcmp(type, "_COUNTER_")) { + ret = HIST_COUNTER_TYPE; + if (tfield->flags & (TEP_FIELD_IS_STRING | TEP_FIELD_IS_ARRAY)) { + parse_error(sb, field->raw, + "'%s' is a string, and counters may only be used with numbers\n"); + ret = -1; + } + goto out; + } + for (i = 0; type[i]; i++) type[i] = tolower(type[i]); @@ -1292,6 +1303,7 @@ static int verify_field_type(struct tep_handle *tep, field->raw, type); ret = -1; } + out: free(type); return ret; fail_type: @@ -1319,6 +1331,7 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, const char *end_match; bool started_start = false; bool started_end = false; + bool non_val = false; int ret; if (!table->from) @@ -1396,6 +1409,8 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, type = verify_field_type(tep, table->sb, expr); if (type < 0) goto free; + if (type != HIST_COUNTER_TYPE) + non_val = true; ret = synth_add_start_field(synth, field->field, field->label, type); @@ -1426,6 +1441,14 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, } } + if (!non_val && !table->to) { + table->sb->line_no = 0; + table->sb->line_idx = 10; + parse_error(table->sb, "CAST", + "Not all SELECT items can be of type _COUNTER_\n"); + goto free; + } + for (expr = table->where; expr; expr = expr->next) { const char *filter_system = NULL; const char *filter_event = NULL;