xref: /openbmc/linux/tools/perf/util/expr.c (revision 3f965a7d)
1576a65b6SJiri Olsa // SPDX-License-Identifier: GPL-2.0
226226a97SJiri Olsa #include <stdbool.h>
3576a65b6SJiri Olsa #include <assert.h>
43744ca1eSArnaldo Carvalho de Melo #include <errno.h>
53744ca1eSArnaldo Carvalho de Melo #include <stdlib.h>
63744ca1eSArnaldo Carvalho de Melo #include <string.h>
7fc393839SJiri Olsa #include "metricgroup.h"
8fc393839SJiri Olsa #include "debug.h"
9576a65b6SJiri Olsa #include "expr.h"
1026226a97SJiri Olsa #include "expr-bison.h"
1126226a97SJiri Olsa #include "expr-flex.h"
12ded80bdaSIan Rogers #include <linux/kernel.h>
13fc393839SJiri Olsa #include <linux/zalloc.h>
14fc393839SJiri Olsa #include <ctype.h>
1526226a97SJiri Olsa 
1626226a97SJiri Olsa #ifdef PARSER_DEBUG
1726226a97SJiri Olsa extern int expr_debug;
1826226a97SJiri Olsa #endif
19576a65b6SJiri Olsa 
2029396cd5SIan Rogers struct expr_id_data {
2129396cd5SIan Rogers 	union {
2229396cd5SIan Rogers 		double val;
2329396cd5SIan Rogers 		struct {
2429396cd5SIan Rogers 			double val;
2529396cd5SIan Rogers 			const char *metric_name;
2629396cd5SIan Rogers 			const char *metric_expr;
2729396cd5SIan Rogers 		} ref;
2829396cd5SIan Rogers 		struct expr_id	*parent;
2929396cd5SIan Rogers 	};
3029396cd5SIan Rogers 
3129396cd5SIan Rogers 	enum {
3229396cd5SIan Rogers 		/* Holding a double value. */
3329396cd5SIan Rogers 		EXPR_ID_DATA__VALUE,
3429396cd5SIan Rogers 		/* Reference to another metric. */
3529396cd5SIan Rogers 		EXPR_ID_DATA__REF,
3629396cd5SIan Rogers 		/* A reference but the value has been computed. */
3729396cd5SIan Rogers 		EXPR_ID_DATA__REF_VALUE,
3829396cd5SIan Rogers 		/* A parent is remembered for the recursion check. */
3929396cd5SIan Rogers 		EXPR_ID_DATA__PARENT,
4029396cd5SIan Rogers 	} kind;
4129396cd5SIan Rogers };
4229396cd5SIan Rogers 
43ded80bdaSIan Rogers static size_t key_hash(const void *key, void *ctx __maybe_unused)
44576a65b6SJiri Olsa {
45ded80bdaSIan Rogers 	const char *str = (const char *)key;
46ded80bdaSIan Rogers 	size_t hash = 0;
47576a65b6SJiri Olsa 
48ded80bdaSIan Rogers 	while (*str != '\0') {
49ded80bdaSIan Rogers 		hash *= 31;
50ded80bdaSIan Rogers 		hash += *str;
51ded80bdaSIan Rogers 		str++;
52ded80bdaSIan Rogers 	}
53ded80bdaSIan Rogers 	return hash;
54ded80bdaSIan Rogers }
55ded80bdaSIan Rogers 
56ded80bdaSIan Rogers static bool key_equal(const void *key1, const void *key2,
57ded80bdaSIan Rogers 		    void *ctx __maybe_unused)
58ded80bdaSIan Rogers {
59ded80bdaSIan Rogers 	return !strcmp((const char *)key1, (const char *)key2);
60ded80bdaSIan Rogers }
61ded80bdaSIan Rogers 
62114a9d6eSIan Rogers struct hashmap *ids__new(void)
63114a9d6eSIan Rogers {
64114a9d6eSIan Rogers 	return hashmap__new(key_hash, key_equal, NULL);
65114a9d6eSIan Rogers }
66114a9d6eSIan Rogers 
67114a9d6eSIan Rogers void ids__free(struct hashmap *ids)
68114a9d6eSIan Rogers {
69114a9d6eSIan Rogers 	struct hashmap_entry *cur;
70114a9d6eSIan Rogers 	size_t bkt;
71114a9d6eSIan Rogers 
72114a9d6eSIan Rogers 	if (ids == NULL)
73114a9d6eSIan Rogers 		return;
74114a9d6eSIan Rogers 
75114a9d6eSIan Rogers 	hashmap__for_each_entry(ids, cur, bkt) {
76114a9d6eSIan Rogers 		free((char *)cur->key);
77114a9d6eSIan Rogers 		free(cur->value);
78114a9d6eSIan Rogers 	}
79114a9d6eSIan Rogers 
80114a9d6eSIan Rogers 	hashmap__free(ids);
81114a9d6eSIan Rogers }
82114a9d6eSIan Rogers 
83114a9d6eSIan Rogers int ids__insert(struct hashmap *ids, const char *id,
84114a9d6eSIan Rogers 		struct expr_id *parent)
85332603c2SJiri Olsa {
86332603c2SJiri Olsa 	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
87332603c2SJiri Olsa 	char *old_key = NULL;
88332603c2SJiri Olsa 	int ret;
89332603c2SJiri Olsa 
90332603c2SJiri Olsa 	data_ptr = malloc(sizeof(*data_ptr));
91332603c2SJiri Olsa 	if (!data_ptr)
92332603c2SJiri Olsa 		return -ENOMEM;
93332603c2SJiri Olsa 
94114a9d6eSIan Rogers 	data_ptr->parent = parent;
9529396cd5SIan Rogers 	data_ptr->kind = EXPR_ID_DATA__PARENT;
96f6fb0960SJiri Olsa 
97114a9d6eSIan Rogers 	ret = hashmap__set(ids, id, data_ptr,
98332603c2SJiri Olsa 			   (const void **)&old_key, (void **)&old_data);
99332603c2SJiri Olsa 	if (ret)
100332603c2SJiri Olsa 		free(data_ptr);
101332603c2SJiri Olsa 	free(old_key);
102332603c2SJiri Olsa 	free(old_data);
103332603c2SJiri Olsa 	return ret;
104332603c2SJiri Olsa }
105332603c2SJiri Olsa 
106114a9d6eSIan Rogers struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2)
107114a9d6eSIan Rogers {
108114a9d6eSIan Rogers 	size_t bkt;
109114a9d6eSIan Rogers 	struct hashmap_entry *cur;
110114a9d6eSIan Rogers 	int ret;
111114a9d6eSIan Rogers 	struct expr_id_data *old_data = NULL;
112114a9d6eSIan Rogers 	char *old_key = NULL;
113114a9d6eSIan Rogers 
114114a9d6eSIan Rogers 	if (!ids1)
115114a9d6eSIan Rogers 		return ids2;
116114a9d6eSIan Rogers 
117114a9d6eSIan Rogers 	if (!ids2)
118114a9d6eSIan Rogers 		return ids1;
119114a9d6eSIan Rogers 
120114a9d6eSIan Rogers 	if (hashmap__size(ids1) <  hashmap__size(ids2)) {
121114a9d6eSIan Rogers 		struct hashmap *tmp = ids1;
122114a9d6eSIan Rogers 
123114a9d6eSIan Rogers 		ids1 = ids2;
124114a9d6eSIan Rogers 		ids2 = tmp;
125114a9d6eSIan Rogers 	}
126114a9d6eSIan Rogers 	hashmap__for_each_entry(ids2, cur, bkt) {
127114a9d6eSIan Rogers 		ret = hashmap__set(ids1, cur->key, cur->value,
128114a9d6eSIan Rogers 				(const void **)&old_key, (void **)&old_data);
129114a9d6eSIan Rogers 		free(old_key);
130114a9d6eSIan Rogers 		free(old_data);
131114a9d6eSIan Rogers 
132114a9d6eSIan Rogers 		if (ret) {
133114a9d6eSIan Rogers 			hashmap__free(ids1);
134114a9d6eSIan Rogers 			hashmap__free(ids2);
135114a9d6eSIan Rogers 			return NULL;
136114a9d6eSIan Rogers 		}
137114a9d6eSIan Rogers 	}
138114a9d6eSIan Rogers 	hashmap__free(ids2);
139114a9d6eSIan Rogers 	return ids1;
140114a9d6eSIan Rogers }
141114a9d6eSIan Rogers 
142114a9d6eSIan Rogers /* Caller must make sure id is allocated */
143114a9d6eSIan Rogers int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
144114a9d6eSIan Rogers {
145114a9d6eSIan Rogers 	return ids__insert(ctx->ids, id, ctx->parent);
146114a9d6eSIan Rogers }
147114a9d6eSIan Rogers 
148332603c2SJiri Olsa /* Caller must make sure id is allocated */
149070b3b5aSJiri Olsa int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
150ded80bdaSIan Rogers {
151070b3b5aSJiri Olsa 	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
152ded80bdaSIan Rogers 	char *old_key = NULL;
153ded80bdaSIan Rogers 	int ret;
154ded80bdaSIan Rogers 
155070b3b5aSJiri Olsa 	data_ptr = malloc(sizeof(*data_ptr));
156070b3b5aSJiri Olsa 	if (!data_ptr)
157ded80bdaSIan Rogers 		return -ENOMEM;
158070b3b5aSJiri Olsa 	data_ptr->val = val;
15929396cd5SIan Rogers 	data_ptr->kind = EXPR_ID_DATA__VALUE;
160332603c2SJiri Olsa 
161cb94a02eSIan Rogers 	ret = hashmap__set(ctx->ids, id, data_ptr,
162070b3b5aSJiri Olsa 			   (const void **)&old_key, (void **)&old_data);
16360e10c00SJiri Olsa 	if (ret)
16460e10c00SJiri Olsa 		free(data_ptr);
165ded80bdaSIan Rogers 	free(old_key);
166070b3b5aSJiri Olsa 	free(old_data);
167ded80bdaSIan Rogers 	return ret;
168ded80bdaSIan Rogers }
169ded80bdaSIan Rogers 
170fc393839SJiri Olsa int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
171fc393839SJiri Olsa {
172fc393839SJiri Olsa 	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
173fc393839SJiri Olsa 	char *old_key = NULL;
174fc393839SJiri Olsa 	char *name, *p;
175fc393839SJiri Olsa 	int ret;
176fc393839SJiri Olsa 
177fc393839SJiri Olsa 	data_ptr = zalloc(sizeof(*data_ptr));
178fc393839SJiri Olsa 	if (!data_ptr)
179fc393839SJiri Olsa 		return -ENOMEM;
180fc393839SJiri Olsa 
181fc393839SJiri Olsa 	name = strdup(ref->metric_name);
182fc393839SJiri Olsa 	if (!name) {
183fc393839SJiri Olsa 		free(data_ptr);
184fc393839SJiri Olsa 		return -ENOMEM;
185fc393839SJiri Olsa 	}
186fc393839SJiri Olsa 
187fc393839SJiri Olsa 	/*
188fc393839SJiri Olsa 	 * The jevents tool converts all metric expressions
189fc393839SJiri Olsa 	 * to lowercase, including metric references, hence
190fc393839SJiri Olsa 	 * we need to add lowercase name for metric, so it's
191fc393839SJiri Olsa 	 * properly found.
192fc393839SJiri Olsa 	 */
193fc393839SJiri Olsa 	for (p = name; *p; p++)
194fc393839SJiri Olsa 		*p = tolower(*p);
195fc393839SJiri Olsa 
196fc393839SJiri Olsa 	/*
197fc393839SJiri Olsa 	 * Intentionally passing just const char pointers,
198fc393839SJiri Olsa 	 * originally from 'struct pmu_event' object.
199fc393839SJiri Olsa 	 * We don't need to change them, so there's no
200fc393839SJiri Olsa 	 * need to create our own copy.
201fc393839SJiri Olsa 	 */
202fc393839SJiri Olsa 	data_ptr->ref.metric_name = ref->metric_name;
203fc393839SJiri Olsa 	data_ptr->ref.metric_expr = ref->metric_expr;
20429396cd5SIan Rogers 	data_ptr->kind = EXPR_ID_DATA__REF;
205fc393839SJiri Olsa 
206cb94a02eSIan Rogers 	ret = hashmap__set(ctx->ids, name, data_ptr,
207fc393839SJiri Olsa 			   (const void **)&old_key, (void **)&old_data);
208fc393839SJiri Olsa 	if (ret)
209fc393839SJiri Olsa 		free(data_ptr);
210fc393839SJiri Olsa 
211fc393839SJiri Olsa 	pr_debug2("adding ref metric %s: %s\n",
212fc393839SJiri Olsa 		  ref->metric_name, ref->metric_expr);
213fc393839SJiri Olsa 
214fc393839SJiri Olsa 	free(old_key);
215fc393839SJiri Olsa 	free(old_data);
216fc393839SJiri Olsa 	return ret;
217fc393839SJiri Olsa }
218fc393839SJiri Olsa 
2195c5f5e83SJiri Olsa int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
2205c5f5e83SJiri Olsa 		 struct expr_id_data **data)
221ded80bdaSIan Rogers {
222cb94a02eSIan Rogers 	return hashmap__find(ctx->ids, id, (void **)data) ? 0 : -1;
223576a65b6SJiri Olsa }
224576a65b6SJiri Olsa 
225acf71b05SJiri Olsa int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
226acf71b05SJiri Olsa 		     struct expr_id_data **datap)
227acf71b05SJiri Olsa {
228acf71b05SJiri Olsa 	struct expr_id_data *data;
229acf71b05SJiri Olsa 
230acf71b05SJiri Olsa 	if (expr__get_id(ctx, id, datap) || !*datap) {
231acf71b05SJiri Olsa 		pr_debug("%s not found\n", id);
232acf71b05SJiri Olsa 		return -1;
233acf71b05SJiri Olsa 	}
234acf71b05SJiri Olsa 
235acf71b05SJiri Olsa 	data = *datap;
236acf71b05SJiri Olsa 
23729396cd5SIan Rogers 	switch (data->kind) {
23829396cd5SIan Rogers 	case EXPR_ID_DATA__VALUE:
23929396cd5SIan Rogers 		pr_debug2("lookup(%s): val %f\n", id, data->val);
24029396cd5SIan Rogers 		break;
24129396cd5SIan Rogers 	case EXPR_ID_DATA__PARENT:
24229396cd5SIan Rogers 		pr_debug2("lookup(%s): parent %s\n", id, data->parent->id);
24329396cd5SIan Rogers 		break;
24429396cd5SIan Rogers 	case EXPR_ID_DATA__REF:
24529396cd5SIan Rogers 		pr_debug2("lookup(%s): ref metric name %s\n", id,
24629396cd5SIan Rogers 			data->ref.metric_name);
247acf71b05SJiri Olsa 		pr_debug("processing metric: %s ENTRY\n", id);
24829396cd5SIan Rogers 		data->kind = EXPR_ID_DATA__REF_VALUE;
24929396cd5SIan Rogers 		if (expr__parse(&data->ref.val, ctx, data->ref.metric_expr, 1)) {
250acf71b05SJiri Olsa 			pr_debug("%s failed to count\n", id);
251acf71b05SJiri Olsa 			return -1;
252acf71b05SJiri Olsa 		}
253acf71b05SJiri Olsa 		pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
25429396cd5SIan Rogers 		break;
25529396cd5SIan Rogers 	case EXPR_ID_DATA__REF_VALUE:
25629396cd5SIan Rogers 		pr_debug2("lookup(%s): ref val %f metric name %s\n", id,
25729396cd5SIan Rogers 			data->ref.val, data->ref.metric_name);
25829396cd5SIan Rogers 		break;
25929396cd5SIan Rogers 	default:
26029396cd5SIan Rogers 		assert(0);  /* Unreachable. */
261acf71b05SJiri Olsa 	}
262acf71b05SJiri Olsa 
263acf71b05SJiri Olsa 	return 0;
264acf71b05SJiri Olsa }
265acf71b05SJiri Olsa 
2663fd29fa6SJiri Olsa void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
2673fd29fa6SJiri Olsa {
2683fd29fa6SJiri Olsa 	struct expr_id_data *old_val = NULL;
2693fd29fa6SJiri Olsa 	char *old_key = NULL;
2703fd29fa6SJiri Olsa 
271cb94a02eSIan Rogers 	hashmap__delete(ctx->ids, id,
2723fd29fa6SJiri Olsa 			(const void **)&old_key, (void **)&old_val);
2733fd29fa6SJiri Olsa 	free(old_key);
2743fd29fa6SJiri Olsa 	free(old_val);
2753fd29fa6SJiri Olsa }
2763fd29fa6SJiri Olsa 
277cb94a02eSIan Rogers struct expr_parse_ctx *expr__ctx_new(void)
278576a65b6SJiri Olsa {
279cb94a02eSIan Rogers 	struct expr_parse_ctx *ctx;
280cb94a02eSIan Rogers 
281cb94a02eSIan Rogers 	ctx = malloc(sizeof(struct expr_parse_ctx));
282cb94a02eSIan Rogers 	if (!ctx)
283cb94a02eSIan Rogers 		return NULL;
284cb94a02eSIan Rogers 
285cb94a02eSIan Rogers 	ctx->ids = hashmap__new(key_hash, key_equal, NULL);
286cb94a02eSIan Rogers 	ctx->parent = NULL;
287cb94a02eSIan Rogers 	return ctx;
288ded80bdaSIan Rogers }
289ded80bdaSIan Rogers 
290ded80bdaSIan Rogers void expr__ctx_clear(struct expr_parse_ctx *ctx)
291ded80bdaSIan Rogers {
292ded80bdaSIan Rogers 	struct hashmap_entry *cur;
293ded80bdaSIan Rogers 	size_t bkt;
294ded80bdaSIan Rogers 
295cb94a02eSIan Rogers 	hashmap__for_each_entry(ctx->ids, cur, bkt) {
296ded80bdaSIan Rogers 		free((char *)cur->key);
297ded80bdaSIan Rogers 		free(cur->value);
298ded80bdaSIan Rogers 	}
299cb94a02eSIan Rogers 	hashmap__clear(ctx->ids);
300cb94a02eSIan Rogers }
301cb94a02eSIan Rogers 
302cb94a02eSIan Rogers void expr__ctx_free(struct expr_parse_ctx *ctx)
303cb94a02eSIan Rogers {
304cb94a02eSIan Rogers 	struct hashmap_entry *cur;
305cb94a02eSIan Rogers 	size_t bkt;
306cb94a02eSIan Rogers 
307cb94a02eSIan Rogers 	hashmap__for_each_entry(ctx->ids, cur, bkt) {
308cb94a02eSIan Rogers 		free((char *)cur->key);
309cb94a02eSIan Rogers 		free(cur->value);
310cb94a02eSIan Rogers 	}
311cb94a02eSIan Rogers 	hashmap__free(ctx->ids);
312cb94a02eSIan Rogers 	free(ctx);
313576a65b6SJiri Olsa }
31426226a97SJiri Olsa 
31526226a97SJiri Olsa static int
316aecce63eSJiri Olsa __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
317*3f965a7dSIan Rogers 	      bool compute_ids, int runtime)
31826226a97SJiri Olsa {
319871f9f59SJiri Olsa 	struct expr_scanner_ctx scanner_ctx = {
3201e1a873dSKajol Jain 		.runtime = runtime,
321871f9f59SJiri Olsa 	};
32226226a97SJiri Olsa 	YY_BUFFER_STATE buffer;
32326226a97SJiri Olsa 	void *scanner;
32426226a97SJiri Olsa 	int ret;
32526226a97SJiri Olsa 
326acf71b05SJiri Olsa 	pr_debug2("parsing metric: %s\n", expr);
327acf71b05SJiri Olsa 
328871f9f59SJiri Olsa 	ret = expr_lex_init_extra(&scanner_ctx, &scanner);
32926226a97SJiri Olsa 	if (ret)
33026226a97SJiri Olsa 		return ret;
33126226a97SJiri Olsa 
33226226a97SJiri Olsa 	buffer = expr__scan_string(expr, scanner);
33326226a97SJiri Olsa 
33426226a97SJiri Olsa #ifdef PARSER_DEBUG
33526226a97SJiri Olsa 	expr_debug = 1;
336e5e0e635SIan Rogers 	expr_set_debug(1, scanner);
33726226a97SJiri Olsa #endif
33826226a97SJiri Olsa 
339*3f965a7dSIan Rogers 	ret = expr_parse(val, ctx, compute_ids, scanner);
34026226a97SJiri Olsa 
34126226a97SJiri Olsa 	expr__flush_buffer(buffer, scanner);
34226226a97SJiri Olsa 	expr__delete_buffer(buffer, scanner);
34326226a97SJiri Olsa 	expr_lex_destroy(scanner);
34426226a97SJiri Olsa 	return ret;
34526226a97SJiri Olsa }
34626226a97SJiri Olsa 
347ded80bdaSIan Rogers int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
348ded80bdaSIan Rogers 		const char *expr, int runtime)
34926226a97SJiri Olsa {
350*3f965a7dSIan Rogers 	return __expr__parse(final_val, ctx, expr, /*compute_ids=*/false, runtime) ? -1 : 0;
35126226a97SJiri Olsa }
35226226a97SJiri Olsa 
3537e06a5e3SIan Rogers int expr__find_ids(const char *expr, const char *one,
354ded80bdaSIan Rogers 		   struct expr_parse_ctx *ctx, int runtime)
35526226a97SJiri Olsa {
356*3f965a7dSIan Rogers 	int ret = __expr__parse(NULL, ctx, expr, /*compute_ids=*/true, runtime);
35726226a97SJiri Olsa 
3583fd29fa6SJiri Olsa 	if (one)
3593fd29fa6SJiri Olsa 		expr__del_id(ctx, one);
36026226a97SJiri Olsa 
361ded80bdaSIan Rogers 	return ret;
36226226a97SJiri Olsa }
36329396cd5SIan Rogers 
36429396cd5SIan Rogers double expr_id_data__value(const struct expr_id_data *data)
36529396cd5SIan Rogers {
36629396cd5SIan Rogers 	if (data->kind == EXPR_ID_DATA__VALUE)
36729396cd5SIan Rogers 		return data->val;
36829396cd5SIan Rogers 	assert(data->kind == EXPR_ID_DATA__REF_VALUE);
36929396cd5SIan Rogers 	return data->ref.val;
37029396cd5SIan Rogers }
37129396cd5SIan Rogers 
37229396cd5SIan Rogers struct expr_id *expr_id_data__parent(struct expr_id_data *data)
37329396cd5SIan Rogers {
37429396cd5SIan Rogers 	assert(data->kind == EXPR_ID_DATA__PARENT);
37529396cd5SIan Rogers 	return data->parent;
37629396cd5SIan Rogers }
377