18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <stdbool.h> 38c2ecf20Sopenharmony_ci#include <assert.h> 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <stdlib.h> 68c2ecf20Sopenharmony_ci#include <string.h> 78c2ecf20Sopenharmony_ci#include "metricgroup.h" 88c2ecf20Sopenharmony_ci#include "debug.h" 98c2ecf20Sopenharmony_ci#include "expr.h" 108c2ecf20Sopenharmony_ci#include "expr-bison.h" 118c2ecf20Sopenharmony_ci#include "expr-flex.h" 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 148c2ecf20Sopenharmony_ci#include <ctype.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#ifdef PARSER_DEBUG 178c2ecf20Sopenharmony_ciextern int expr_debug; 188c2ecf20Sopenharmony_ci#endif 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic size_t key_hash(const void *key, void *ctx __maybe_unused) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci const char *str = (const char *)key; 238c2ecf20Sopenharmony_ci size_t hash = 0; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci while (*str != '\0') { 268c2ecf20Sopenharmony_ci hash *= 31; 278c2ecf20Sopenharmony_ci hash += *str; 288c2ecf20Sopenharmony_ci str++; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci return hash; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic bool key_equal(const void *key1, const void *key2, 348c2ecf20Sopenharmony_ci void *ctx __maybe_unused) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci return !strcmp((const char *)key1, (const char *)key2); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Caller must make sure id is allocated */ 408c2ecf20Sopenharmony_ciint expr__add_id(struct expr_parse_ctx *ctx, const char *id) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct expr_id_data *data_ptr = NULL, *old_data = NULL; 438c2ecf20Sopenharmony_ci char *old_key = NULL; 448c2ecf20Sopenharmony_ci int ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci data_ptr = malloc(sizeof(*data_ptr)); 478c2ecf20Sopenharmony_ci if (!data_ptr) 488c2ecf20Sopenharmony_ci return -ENOMEM; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci data_ptr->parent = ctx->parent; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci ret = hashmap__set(&ctx->ids, id, data_ptr, 538c2ecf20Sopenharmony_ci (const void **)&old_key, (void **)&old_data); 548c2ecf20Sopenharmony_ci if (ret) 558c2ecf20Sopenharmony_ci free(data_ptr); 568c2ecf20Sopenharmony_ci free(old_key); 578c2ecf20Sopenharmony_ci free(old_data); 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* Caller must make sure id is allocated */ 628c2ecf20Sopenharmony_ciint expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct expr_id_data *data_ptr = NULL, *old_data = NULL; 658c2ecf20Sopenharmony_ci char *old_key = NULL; 668c2ecf20Sopenharmony_ci int ret; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci data_ptr = malloc(sizeof(*data_ptr)); 698c2ecf20Sopenharmony_ci if (!data_ptr) 708c2ecf20Sopenharmony_ci return -ENOMEM; 718c2ecf20Sopenharmony_ci data_ptr->val = val; 728c2ecf20Sopenharmony_ci data_ptr->is_ref = false; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci ret = hashmap__set(&ctx->ids, id, data_ptr, 758c2ecf20Sopenharmony_ci (const void **)&old_key, (void **)&old_data); 768c2ecf20Sopenharmony_ci if (ret) 778c2ecf20Sopenharmony_ci free(data_ptr); 788c2ecf20Sopenharmony_ci free(old_key); 798c2ecf20Sopenharmony_ci free(old_data); 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct expr_id_data *data_ptr = NULL, *old_data = NULL; 868c2ecf20Sopenharmony_ci char *old_key = NULL; 878c2ecf20Sopenharmony_ci char *name, *p; 888c2ecf20Sopenharmony_ci int ret; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci data_ptr = zalloc(sizeof(*data_ptr)); 918c2ecf20Sopenharmony_ci if (!data_ptr) 928c2ecf20Sopenharmony_ci return -ENOMEM; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci name = strdup(ref->metric_name); 958c2ecf20Sopenharmony_ci if (!name) { 968c2ecf20Sopenharmony_ci free(data_ptr); 978c2ecf20Sopenharmony_ci return -ENOMEM; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* 1018c2ecf20Sopenharmony_ci * The jevents tool converts all metric expressions 1028c2ecf20Sopenharmony_ci * to lowercase, including metric references, hence 1038c2ecf20Sopenharmony_ci * we need to add lowercase name for metric, so it's 1048c2ecf20Sopenharmony_ci * properly found. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci for (p = name; *p; p++) 1078c2ecf20Sopenharmony_ci *p = tolower(*p); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Intentionally passing just const char pointers, 1118c2ecf20Sopenharmony_ci * originally from 'struct pmu_event' object. 1128c2ecf20Sopenharmony_ci * We don't need to change them, so there's no 1138c2ecf20Sopenharmony_ci * need to create our own copy. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci data_ptr->ref.metric_name = ref->metric_name; 1168c2ecf20Sopenharmony_ci data_ptr->ref.metric_expr = ref->metric_expr; 1178c2ecf20Sopenharmony_ci data_ptr->ref.counted = false; 1188c2ecf20Sopenharmony_ci data_ptr->is_ref = true; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ret = hashmap__set(&ctx->ids, name, data_ptr, 1218c2ecf20Sopenharmony_ci (const void **)&old_key, (void **)&old_data); 1228c2ecf20Sopenharmony_ci if (ret) 1238c2ecf20Sopenharmony_ci free(data_ptr); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci pr_debug2("adding ref metric %s: %s\n", 1268c2ecf20Sopenharmony_ci ref->metric_name, ref->metric_expr); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci free(old_key); 1298c2ecf20Sopenharmony_ci free(old_data); 1308c2ecf20Sopenharmony_ci return ret; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciint expr__get_id(struct expr_parse_ctx *ctx, const char *id, 1348c2ecf20Sopenharmony_ci struct expr_id_data **data) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciint expr__resolve_id(struct expr_parse_ctx *ctx, const char *id, 1408c2ecf20Sopenharmony_ci struct expr_id_data **datap) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct expr_id_data *data; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (expr__get_id(ctx, id, datap) || !*datap) { 1458c2ecf20Sopenharmony_ci pr_debug("%s not found\n", id); 1468c2ecf20Sopenharmony_ci return -1; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci data = *datap; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n", 1528c2ecf20Sopenharmony_ci data->is_ref, data->ref.counted, data->val, id); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (data->is_ref && !data->ref.counted) { 1558c2ecf20Sopenharmony_ci data->ref.counted = true; 1568c2ecf20Sopenharmony_ci pr_debug("processing metric: %s ENTRY\n", id); 1578c2ecf20Sopenharmony_ci if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) { 1588c2ecf20Sopenharmony_ci pr_debug("%s failed to count\n", id); 1598c2ecf20Sopenharmony_ci return -1; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci pr_debug("processing metric: %s EXIT: %f\n", id, data->val); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_civoid expr__del_id(struct expr_parse_ctx *ctx, const char *id) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct expr_id_data *old_val = NULL; 1708c2ecf20Sopenharmony_ci char *old_key = NULL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci hashmap__delete(&ctx->ids, id, 1738c2ecf20Sopenharmony_ci (const void **)&old_key, (void **)&old_val); 1748c2ecf20Sopenharmony_ci free(old_key); 1758c2ecf20Sopenharmony_ci free(old_val); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_civoid expr__ctx_init(struct expr_parse_ctx *ctx) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci hashmap__init(&ctx->ids, key_hash, key_equal, NULL); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_civoid expr__ctx_clear(struct expr_parse_ctx *ctx) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct hashmap_entry *cur; 1868c2ecf20Sopenharmony_ci size_t bkt; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci hashmap__for_each_entry((&ctx->ids), cur, bkt) { 1898c2ecf20Sopenharmony_ci free((char *)cur->key); 1908c2ecf20Sopenharmony_ci free(cur->value); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci hashmap__clear(&ctx->ids); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int 1968c2ecf20Sopenharmony_ci__expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr, 1978c2ecf20Sopenharmony_ci int start, int runtime) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct expr_scanner_ctx scanner_ctx = { 2008c2ecf20Sopenharmony_ci .start_token = start, 2018c2ecf20Sopenharmony_ci .runtime = runtime, 2028c2ecf20Sopenharmony_ci }; 2038c2ecf20Sopenharmony_ci YY_BUFFER_STATE buffer; 2048c2ecf20Sopenharmony_ci void *scanner; 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci pr_debug2("parsing metric: %s\n", expr); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = expr_lex_init_extra(&scanner_ctx, &scanner); 2108c2ecf20Sopenharmony_ci if (ret) 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci buffer = expr__scan_string(expr, scanner); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#ifdef PARSER_DEBUG 2168c2ecf20Sopenharmony_ci expr_debug = 1; 2178c2ecf20Sopenharmony_ci expr_set_debug(1, scanner); 2188c2ecf20Sopenharmony_ci#endif 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = expr_parse(val, ctx, scanner); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci expr__flush_buffer(buffer, scanner); 2238c2ecf20Sopenharmony_ci expr__delete_buffer(buffer, scanner); 2248c2ecf20Sopenharmony_ci expr_lex_destroy(scanner); 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint expr__parse(double *final_val, struct expr_parse_ctx *ctx, 2298c2ecf20Sopenharmony_ci const char *expr, int runtime) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci return __expr__parse(final_val, ctx, expr, EXPR_PARSE, runtime) ? -1 : 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciint expr__find_other(const char *expr, const char *one, 2358c2ecf20Sopenharmony_ci struct expr_parse_ctx *ctx, int runtime) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (one) 2408c2ecf20Sopenharmony_ci expr__del_id(ctx, one); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci} 244