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