1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdbool.h> 3 #include <assert.h> 4 #include <errno.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include "metricgroup.h" 8 #include "debug.h" 9 #include "expr.h" 10 #include "expr-bison.h" 11 #include "expr-flex.h" 12 #include <linux/kernel.h> 13 #include <linux/zalloc.h> 14 #include <ctype.h> 15 16 #ifdef PARSER_DEBUG 17 extern int expr_debug; 18 #endif 19 20 struct expr_id_data { 21 union { 22 double val; 23 struct { 24 double val; 25 const char *metric_name; 26 const char *metric_expr; 27 } ref; 28 struct expr_id *parent; 29 }; 30 31 enum { 32 /* Holding a double value. */ 33 EXPR_ID_DATA__VALUE, 34 /* Reference to another metric. */ 35 EXPR_ID_DATA__REF, 36 /* A reference but the value has been computed. */ 37 EXPR_ID_DATA__REF_VALUE, 38 /* A parent is remembered for the recursion check. */ 39 EXPR_ID_DATA__PARENT, 40 } kind; 41 }; 42 43 static size_t key_hash(const void *key, void *ctx __maybe_unused) 44 { 45 const char *str = (const char *)key; 46 size_t hash = 0; 47 48 while (*str != '\0') { 49 hash *= 31; 50 hash += *str; 51 str++; 52 } 53 return hash; 54 } 55 56 static bool key_equal(const void *key1, const void *key2, 57 void *ctx __maybe_unused) 58 { 59 return !strcmp((const char *)key1, (const char *)key2); 60 } 61 62 struct hashmap *ids__new(void) 63 { 64 return hashmap__new(key_hash, key_equal, NULL); 65 } 66 67 void ids__free(struct hashmap *ids) 68 { 69 struct hashmap_entry *cur; 70 size_t bkt; 71 72 if (ids == NULL) 73 return; 74 75 hashmap__for_each_entry(ids, cur, bkt) { 76 free((char *)cur->key); 77 free(cur->value); 78 } 79 80 hashmap__free(ids); 81 } 82 83 int ids__insert(struct hashmap *ids, const char *id, 84 struct expr_id *parent) 85 { 86 struct expr_id_data *data_ptr = NULL, *old_data = NULL; 87 char *old_key = NULL; 88 int ret; 89 90 data_ptr = malloc(sizeof(*data_ptr)); 91 if (!data_ptr) 92 return -ENOMEM; 93 94 data_ptr->parent = parent; 95 data_ptr->kind = EXPR_ID_DATA__PARENT; 96 97 ret = hashmap__set(ids, id, data_ptr, 98 (const void **)&old_key, (void **)&old_data); 99 if (ret) 100 free(data_ptr); 101 free(old_key); 102 free(old_data); 103 return ret; 104 } 105 106 struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2) 107 { 108 size_t bkt; 109 struct hashmap_entry *cur; 110 int ret; 111 struct expr_id_data *old_data = NULL; 112 char *old_key = NULL; 113 114 if (!ids1) 115 return ids2; 116 117 if (!ids2) 118 return ids1; 119 120 if (hashmap__size(ids1) < hashmap__size(ids2)) { 121 struct hashmap *tmp = ids1; 122 123 ids1 = ids2; 124 ids2 = tmp; 125 } 126 hashmap__for_each_entry(ids2, cur, bkt) { 127 ret = hashmap__set(ids1, cur->key, cur->value, 128 (const void **)&old_key, (void **)&old_data); 129 free(old_key); 130 free(old_data); 131 132 if (ret) { 133 hashmap__free(ids1); 134 hashmap__free(ids2); 135 return NULL; 136 } 137 } 138 hashmap__free(ids2); 139 return ids1; 140 } 141 142 /* Caller must make sure id is allocated */ 143 int expr__add_id(struct expr_parse_ctx *ctx, const char *id) 144 { 145 return ids__insert(ctx->ids, id, ctx->parent); 146 } 147 148 /* Caller must make sure id is allocated */ 149 int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val) 150 { 151 struct expr_id_data *data_ptr = NULL, *old_data = NULL; 152 char *old_key = NULL; 153 int ret; 154 155 data_ptr = malloc(sizeof(*data_ptr)); 156 if (!data_ptr) 157 return -ENOMEM; 158 data_ptr->val = val; 159 data_ptr->kind = EXPR_ID_DATA__VALUE; 160 161 ret = hashmap__set(ctx->ids, id, data_ptr, 162 (const void **)&old_key, (void **)&old_data); 163 if (ret) 164 free(data_ptr); 165 free(old_key); 166 free(old_data); 167 return ret; 168 } 169 170 int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref) 171 { 172 struct expr_id_data *data_ptr = NULL, *old_data = NULL; 173 char *old_key = NULL; 174 char *name, *p; 175 int ret; 176 177 data_ptr = zalloc(sizeof(*data_ptr)); 178 if (!data_ptr) 179 return -ENOMEM; 180 181 name = strdup(ref->metric_name); 182 if (!name) { 183 free(data_ptr); 184 return -ENOMEM; 185 } 186 187 /* 188 * The jevents tool converts all metric expressions 189 * to lowercase, including metric references, hence 190 * we need to add lowercase name for metric, so it's 191 * properly found. 192 */ 193 for (p = name; *p; p++) 194 *p = tolower(*p); 195 196 /* 197 * Intentionally passing just const char pointers, 198 * originally from 'struct pmu_event' object. 199 * We don't need to change them, so there's no 200 * need to create our own copy. 201 */ 202 data_ptr->ref.metric_name = ref->metric_name; 203 data_ptr->ref.metric_expr = ref->metric_expr; 204 data_ptr->kind = EXPR_ID_DATA__REF; 205 206 ret = hashmap__set(ctx->ids, name, data_ptr, 207 (const void **)&old_key, (void **)&old_data); 208 if (ret) 209 free(data_ptr); 210 211 pr_debug2("adding ref metric %s: %s\n", 212 ref->metric_name, ref->metric_expr); 213 214 free(old_key); 215 free(old_data); 216 return ret; 217 } 218 219 int expr__get_id(struct expr_parse_ctx *ctx, const char *id, 220 struct expr_id_data **data) 221 { 222 return hashmap__find(ctx->ids, id, (void **)data) ? 0 : -1; 223 } 224 225 int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id, 226 struct expr_id_data **datap) 227 { 228 struct expr_id_data *data; 229 230 if (expr__get_id(ctx, id, datap) || !*datap) { 231 pr_debug("%s not found\n", id); 232 return -1; 233 } 234 235 data = *datap; 236 237 switch (data->kind) { 238 case EXPR_ID_DATA__VALUE: 239 pr_debug2("lookup(%s): val %f\n", id, data->val); 240 break; 241 case EXPR_ID_DATA__PARENT: 242 pr_debug2("lookup(%s): parent %s\n", id, data->parent->id); 243 break; 244 case EXPR_ID_DATA__REF: 245 pr_debug2("lookup(%s): ref metric name %s\n", id, 246 data->ref.metric_name); 247 pr_debug("processing metric: %s ENTRY\n", id); 248 data->kind = EXPR_ID_DATA__REF_VALUE; 249 if (expr__parse(&data->ref.val, ctx, data->ref.metric_expr)) { 250 pr_debug("%s failed to count\n", id); 251 return -1; 252 } 253 pr_debug("processing metric: %s EXIT: %f\n", id, data->val); 254 break; 255 case EXPR_ID_DATA__REF_VALUE: 256 pr_debug2("lookup(%s): ref val %f metric name %s\n", id, 257 data->ref.val, data->ref.metric_name); 258 break; 259 default: 260 assert(0); /* Unreachable. */ 261 } 262 263 return 0; 264 } 265 266 void expr__del_id(struct expr_parse_ctx *ctx, const char *id) 267 { 268 struct expr_id_data *old_val = NULL; 269 char *old_key = NULL; 270 271 hashmap__delete(ctx->ids, id, 272 (const void **)&old_key, (void **)&old_val); 273 free(old_key); 274 free(old_val); 275 } 276 277 struct expr_parse_ctx *expr__ctx_new(void) 278 { 279 struct expr_parse_ctx *ctx; 280 281 ctx = malloc(sizeof(struct expr_parse_ctx)); 282 if (!ctx) 283 return NULL; 284 285 ctx->ids = hashmap__new(key_hash, key_equal, NULL); 286 ctx->parent = NULL; 287 ctx->runtime = 0; 288 return ctx; 289 } 290 291 void expr__ctx_clear(struct expr_parse_ctx *ctx) 292 { 293 struct hashmap_entry *cur; 294 size_t bkt; 295 296 hashmap__for_each_entry(ctx->ids, cur, bkt) { 297 free((char *)cur->key); 298 free(cur->value); 299 } 300 hashmap__clear(ctx->ids); 301 } 302 303 void expr__ctx_free(struct expr_parse_ctx *ctx) 304 { 305 struct hashmap_entry *cur; 306 size_t bkt; 307 308 hashmap__for_each_entry(ctx->ids, cur, bkt) { 309 free((char *)cur->key); 310 free(cur->value); 311 } 312 hashmap__free(ctx->ids); 313 free(ctx); 314 } 315 316 static int 317 __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr, 318 bool compute_ids) 319 { 320 struct expr_scanner_ctx scanner_ctx = { 321 .runtime = ctx->runtime, 322 }; 323 YY_BUFFER_STATE buffer; 324 void *scanner; 325 int ret; 326 327 pr_debug2("parsing metric: %s\n", expr); 328 329 ret = expr_lex_init_extra(&scanner_ctx, &scanner); 330 if (ret) 331 return ret; 332 333 buffer = expr__scan_string(expr, scanner); 334 335 #ifdef PARSER_DEBUG 336 expr_debug = 1; 337 expr_set_debug(1, scanner); 338 #endif 339 340 ret = expr_parse(val, ctx, compute_ids, scanner); 341 342 expr__flush_buffer(buffer, scanner); 343 expr__delete_buffer(buffer, scanner); 344 expr_lex_destroy(scanner); 345 return ret; 346 } 347 348 int expr__parse(double *final_val, struct expr_parse_ctx *ctx, 349 const char *expr) 350 { 351 return __expr__parse(final_val, ctx, expr, /*compute_ids=*/false) ? -1 : 0; 352 } 353 354 int expr__find_ids(const char *expr, const char *one, 355 struct expr_parse_ctx *ctx) 356 { 357 int ret = __expr__parse(NULL, ctx, expr, /*compute_ids=*/true); 358 359 if (one) 360 expr__del_id(ctx, one); 361 362 return ret; 363 } 364 365 double expr_id_data__value(const struct expr_id_data *data) 366 { 367 if (data->kind == EXPR_ID_DATA__VALUE) 368 return data->val; 369 assert(data->kind == EXPR_ID_DATA__REF_VALUE); 370 return data->ref.val; 371 } 372 373 struct expr_id *expr_id_data__parent(struct expr_id_data *data) 374 { 375 assert(data->kind == EXPR_ID_DATA__PARENT); 376 return data->parent; 377 } 378