Merge tag 'for-5.9-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / tools / perf / util / expr.c
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 static 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
33 static 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 */
40 int 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 */
62 int 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
83 int 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
133 int 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
139 int 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
167 void 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
178 void expr__ctx_init(struct expr_parse_ctx *ctx)
179 {
180         hashmap__init(&ctx->ids, key_hash, key_equal, NULL);
181 }
182
183 void 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
195 static 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
228 int 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
234 int 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 }