linux/tools/perf/util/expr.c
<<
>>
Prefs
   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
  17extern int expr_debug;
  18#endif
  19
  20static size_t key_hash(const void *key, void *ctx __maybe_unused)
  21{
  22        const char *str = (const char *)key;
  23        size_t hash = 0;
  24
  25        while (*str != '\0') {
  26                hash *= 31;
  27                hash += *str;
  28                str++;
  29        }
  30        return hash;
  31}
  32
  33static bool key_equal(const void *key1, const void *key2,
  34                    void *ctx __maybe_unused)
  35{
  36        return !strcmp((const char *)key1, (const char *)key2);
  37}
  38
  39/* Caller must make sure id is allocated */
  40int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
  41{
  42        struct expr_id_data *data_ptr = NULL, *old_data = NULL;
  43        char *old_key = NULL;
  44        int ret;
  45
  46        data_ptr = malloc(sizeof(*data_ptr));
  47        if (!data_ptr)
  48                return -ENOMEM;
  49
  50        data_ptr->parent = ctx->parent;
  51
  52        ret = hashmap__set(&ctx->ids, id, data_ptr,
  53                           (const void **)&old_key, (void **)&old_data);
  54        if (ret)
  55                free(data_ptr);
  56        free(old_key);
  57        free(old_data);
  58        return ret;
  59}
  60
  61/* Caller must make sure id is allocated */
  62int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
  63{
  64        struct expr_id_data *data_ptr = NULL, *old_data = NULL;
  65        char *old_key = NULL;
  66        int ret;
  67
  68        data_ptr = malloc(sizeof(*data_ptr));
  69        if (!data_ptr)
  70                return -ENOMEM;
  71        data_ptr->val = val;
  72        data_ptr->is_ref = false;
  73
  74        ret = hashmap__set(&ctx->ids, id, data_ptr,
  75                           (const void **)&old_key, (void **)&old_data);
  76        if (ret)
  77                free(data_ptr);
  78        free(old_key);
  79        free(old_data);
  80        return ret;
  81}
  82
  83int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
  84{
  85        struct expr_id_data *data_ptr = NULL, *old_data = NULL;
  86        char *old_key = NULL;
  87        char *name, *p;
  88        int ret;
  89
  90        data_ptr = zalloc(sizeof(*data_ptr));
  91        if (!data_ptr)
  92                return -ENOMEM;
  93
  94        name = strdup(ref->metric_name);
  95        if (!name) {
  96                free(data_ptr);
  97                return -ENOMEM;
  98        }
  99
 100        /*
 101         * The jevents tool converts all metric expressions
 102         * to lowercase, including metric references, hence
 103         * we need to add lowercase name for metric, so it's
 104         * properly found.
 105         */
 106        for (p = name; *p; p++)
 107                *p = tolower(*p);
 108
 109        /*
 110         * Intentionally passing just const char pointers,
 111         * originally from 'struct pmu_event' object.
 112         * We don't need to change them, so there's no
 113         * need to create our own copy.
 114         */
 115        data_ptr->ref.metric_name = ref->metric_name;
 116        data_ptr->ref.metric_expr = ref->metric_expr;
 117        data_ptr->ref.counted = false;
 118        data_ptr->is_ref = true;
 119
 120        ret = hashmap__set(&ctx->ids, name, data_ptr,
 121                           (const void **)&old_key, (void **)&old_data);
 122        if (ret)
 123                free(data_ptr);
 124
 125        pr_debug2("adding ref metric %s: %s\n",
 126                  ref->metric_name, ref->metric_expr);
 127
 128        free(old_key);
 129        free(old_data);
 130        return ret;
 131}
 132
 133int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
 134                 struct expr_id_data **data)
 135{
 136        return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
 137}
 138
 139int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
 140                     struct expr_id_data **datap)
 141{
 142        struct expr_id_data *data;
 143
 144        if (expr__get_id(ctx, id, datap) || !*datap) {
 145                pr_debug("%s not found\n", id);
 146                return -1;
 147        }
 148
 149        data = *datap;
 150
 151        pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n",
 152                  data->is_ref, data->ref.counted, data->val, id);
 153
 154        if (data->is_ref && !data->ref.counted) {
 155                data->ref.counted = true;
 156                pr_debug("processing metric: %s ENTRY\n", id);
 157                if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) {
 158                        pr_debug("%s failed to count\n", id);
 159                        return -1;
 160                }
 161                pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
 162        }
 163
 164        return 0;
 165}
 166
 167void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
 168{
 169        struct expr_id_data *old_val = NULL;
 170        char *old_key = NULL;
 171
 172        hashmap__delete(&ctx->ids, id,
 173                        (const void **)&old_key, (void **)&old_val);
 174        free(old_key);
 175        free(old_val);
 176}
 177
 178void expr__ctx_init(struct expr_parse_ctx *ctx)
 179{
 180        hashmap__init(&ctx->ids, key_hash, key_equal, NULL);
 181}
 182
 183void expr__ctx_clear(struct expr_parse_ctx *ctx)
 184{
 185        struct hashmap_entry *cur;
 186        size_t bkt;
 187
 188        hashmap__for_each_entry((&ctx->ids), cur, bkt) {
 189                free((char *)cur->key);
 190                free(cur->value);
 191        }
 192        hashmap__clear(&ctx->ids);
 193}
 194
 195static int
 196__expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
 197              int start, int runtime)
 198{
 199        struct expr_scanner_ctx scanner_ctx = {
 200                .start_token = start,
 201                .runtime = runtime,
 202        };
 203        YY_BUFFER_STATE buffer;
 204        void *scanner;
 205        int ret;
 206
 207        pr_debug2("parsing metric: %s\n", expr);
 208
 209        ret = expr_lex_init_extra(&scanner_ctx, &scanner);
 210        if (ret)
 211                return ret;
 212
 213        buffer = expr__scan_string(expr, scanner);
 214
 215#ifdef PARSER_DEBUG
 216        expr_debug = 1;
 217        expr_set_debug(1, scanner);
 218#endif
 219
 220        ret = expr_parse(val, ctx, scanner);
 221
 222        expr__flush_buffer(buffer, scanner);
 223        expr__delete_buffer(buffer, scanner);
 224        expr_lex_destroy(scanner);
 225        return ret;
 226}
 227
 228int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
 229                const char *expr, int runtime)
 230{
 231        return __expr__parse(final_val, ctx, expr, EXPR_PARSE, runtime) ? -1 : 0;
 232}
 233
 234int expr__find_other(const char *expr, const char *one,
 235                     struct expr_parse_ctx *ctx, int runtime)
 236{
 237        int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime);
 238
 239        if (one)
 240                expr__del_id(ctx, one);
 241
 242        return ret;
 243}
 244