xref: /openbmc/linux/tools/perf/util/expr.c (revision 29396cd5)
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 
20*29396cd5SIan Rogers struct expr_id_data {
21*29396cd5SIan Rogers 	union {
22*29396cd5SIan Rogers 		double val;
23*29396cd5SIan Rogers 		struct {
24*29396cd5SIan Rogers 			double val;
25*29396cd5SIan Rogers 			const char *metric_name;
26*29396cd5SIan Rogers 			const char *metric_expr;
27*29396cd5SIan Rogers 		} ref;
28*29396cd5SIan Rogers 		struct expr_id	*parent;
29*29396cd5SIan Rogers 	};
30*29396cd5SIan Rogers 
31*29396cd5SIan Rogers 	enum {
32*29396cd5SIan Rogers 		/* Holding a double value. */
33*29396cd5SIan Rogers 		EXPR_ID_DATA__VALUE,
34*29396cd5SIan Rogers 		/* Reference to another metric. */
35*29396cd5SIan Rogers 		EXPR_ID_DATA__REF,
36*29396cd5SIan Rogers 		/* A reference but the value has been computed. */
37*29396cd5SIan Rogers 		EXPR_ID_DATA__REF_VALUE,
38*29396cd5SIan Rogers 		/* A parent is remembered for the recursion check. */
39*29396cd5SIan Rogers 		EXPR_ID_DATA__PARENT,
40*29396cd5SIan Rogers 	} kind;
41*29396cd5SIan Rogers };
42*29396cd5SIan 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 
62ded80bdaSIan Rogers /* Caller must make sure id is allocated */
63332603c2SJiri Olsa int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
64332603c2SJiri Olsa {
65332603c2SJiri Olsa 	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
66332603c2SJiri Olsa 	char *old_key = NULL;
67332603c2SJiri Olsa 	int ret;
68332603c2SJiri Olsa 
69332603c2SJiri Olsa 	data_ptr = malloc(sizeof(*data_ptr));
70332603c2SJiri Olsa 	if (!data_ptr)
71332603c2SJiri Olsa 		return -ENOMEM;
72332603c2SJiri Olsa 
73f6fb0960SJiri Olsa 	data_ptr->parent = ctx->parent;
74*29396cd5SIan Rogers 	data_ptr->kind = EXPR_ID_DATA__PARENT;
75f6fb0960SJiri Olsa 
76332603c2SJiri Olsa 	ret = hashmap__set(&ctx->ids, id, data_ptr,
77332603c2SJiri Olsa 			   (const void **)&old_key, (void **)&old_data);
78332603c2SJiri Olsa 	if (ret)
79332603c2SJiri Olsa 		free(data_ptr);
80332603c2SJiri Olsa 	free(old_key);
81332603c2SJiri Olsa 	free(old_data);
82332603c2SJiri Olsa 	return ret;
83332603c2SJiri Olsa }
84332603c2SJiri Olsa 
85332603c2SJiri Olsa /* Caller must make sure id is allocated */
86070b3b5aSJiri Olsa int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
87ded80bdaSIan Rogers {
88070b3b5aSJiri Olsa 	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
89ded80bdaSIan Rogers 	char *old_key = NULL;
90ded80bdaSIan Rogers 	int ret;
91ded80bdaSIan Rogers 
92070b3b5aSJiri Olsa 	data_ptr = malloc(sizeof(*data_ptr));
93070b3b5aSJiri Olsa 	if (!data_ptr)
94ded80bdaSIan Rogers 		return -ENOMEM;
95070b3b5aSJiri Olsa 	data_ptr->val = val;
96*29396cd5SIan Rogers 	data_ptr->kind = EXPR_ID_DATA__VALUE;
97332603c2SJiri Olsa 
98070b3b5aSJiri Olsa 	ret = hashmap__set(&ctx->ids, id, data_ptr,
99070b3b5aSJiri Olsa 			   (const void **)&old_key, (void **)&old_data);
10060e10c00SJiri Olsa 	if (ret)
10160e10c00SJiri Olsa 		free(data_ptr);
102ded80bdaSIan Rogers 	free(old_key);
103070b3b5aSJiri Olsa 	free(old_data);
104ded80bdaSIan Rogers 	return ret;
105ded80bdaSIan Rogers }
106ded80bdaSIan Rogers 
107fc393839SJiri Olsa int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
108fc393839SJiri Olsa {
109fc393839SJiri Olsa 	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
110fc393839SJiri Olsa 	char *old_key = NULL;
111fc393839SJiri Olsa 	char *name, *p;
112fc393839SJiri Olsa 	int ret;
113fc393839SJiri Olsa 
114fc393839SJiri Olsa 	data_ptr = zalloc(sizeof(*data_ptr));
115fc393839SJiri Olsa 	if (!data_ptr)
116fc393839SJiri Olsa 		return -ENOMEM;
117fc393839SJiri Olsa 
118fc393839SJiri Olsa 	name = strdup(ref->metric_name);
119fc393839SJiri Olsa 	if (!name) {
120fc393839SJiri Olsa 		free(data_ptr);
121fc393839SJiri Olsa 		return -ENOMEM;
122fc393839SJiri Olsa 	}
123fc393839SJiri Olsa 
124fc393839SJiri Olsa 	/*
125fc393839SJiri Olsa 	 * The jevents tool converts all metric expressions
126fc393839SJiri Olsa 	 * to lowercase, including metric references, hence
127fc393839SJiri Olsa 	 * we need to add lowercase name for metric, so it's
128fc393839SJiri Olsa 	 * properly found.
129fc393839SJiri Olsa 	 */
130fc393839SJiri Olsa 	for (p = name; *p; p++)
131fc393839SJiri Olsa 		*p = tolower(*p);
132fc393839SJiri Olsa 
133fc393839SJiri Olsa 	/*
134fc393839SJiri Olsa 	 * Intentionally passing just const char pointers,
135fc393839SJiri Olsa 	 * originally from 'struct pmu_event' object.
136fc393839SJiri Olsa 	 * We don't need to change them, so there's no
137fc393839SJiri Olsa 	 * need to create our own copy.
138fc393839SJiri Olsa 	 */
139fc393839SJiri Olsa 	data_ptr->ref.metric_name = ref->metric_name;
140fc393839SJiri Olsa 	data_ptr->ref.metric_expr = ref->metric_expr;
141*29396cd5SIan Rogers 	data_ptr->kind = EXPR_ID_DATA__REF;
142fc393839SJiri Olsa 
143fc393839SJiri Olsa 	ret = hashmap__set(&ctx->ids, name, data_ptr,
144fc393839SJiri Olsa 			   (const void **)&old_key, (void **)&old_data);
145fc393839SJiri Olsa 	if (ret)
146fc393839SJiri Olsa 		free(data_ptr);
147fc393839SJiri Olsa 
148fc393839SJiri Olsa 	pr_debug2("adding ref metric %s: %s\n",
149fc393839SJiri Olsa 		  ref->metric_name, ref->metric_expr);
150fc393839SJiri Olsa 
151fc393839SJiri Olsa 	free(old_key);
152fc393839SJiri Olsa 	free(old_data);
153fc393839SJiri Olsa 	return ret;
154fc393839SJiri Olsa }
155fc393839SJiri Olsa 
1565c5f5e83SJiri Olsa int expr__get_id(struct expr_parse_ctx *ctx, const char *id,
1575c5f5e83SJiri Olsa 		 struct expr_id_data **data)
158ded80bdaSIan Rogers {
1595c5f5e83SJiri Olsa 	return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1;
160576a65b6SJiri Olsa }
161576a65b6SJiri Olsa 
162acf71b05SJiri Olsa int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
163acf71b05SJiri Olsa 		     struct expr_id_data **datap)
164acf71b05SJiri Olsa {
165acf71b05SJiri Olsa 	struct expr_id_data *data;
166acf71b05SJiri Olsa 
167acf71b05SJiri Olsa 	if (expr__get_id(ctx, id, datap) || !*datap) {
168acf71b05SJiri Olsa 		pr_debug("%s not found\n", id);
169acf71b05SJiri Olsa 		return -1;
170acf71b05SJiri Olsa 	}
171acf71b05SJiri Olsa 
172acf71b05SJiri Olsa 	data = *datap;
173acf71b05SJiri Olsa 
174*29396cd5SIan Rogers 	switch (data->kind) {
175*29396cd5SIan Rogers 	case EXPR_ID_DATA__VALUE:
176*29396cd5SIan Rogers 		pr_debug2("lookup(%s): val %f\n", id, data->val);
177*29396cd5SIan Rogers 		break;
178*29396cd5SIan Rogers 	case EXPR_ID_DATA__PARENT:
179*29396cd5SIan Rogers 		pr_debug2("lookup(%s): parent %s\n", id, data->parent->id);
180*29396cd5SIan Rogers 		break;
181*29396cd5SIan Rogers 	case EXPR_ID_DATA__REF:
182*29396cd5SIan Rogers 		pr_debug2("lookup(%s): ref metric name %s\n", id,
183*29396cd5SIan Rogers 			data->ref.metric_name);
184acf71b05SJiri Olsa 		pr_debug("processing metric: %s ENTRY\n", id);
185*29396cd5SIan Rogers 		data->kind = EXPR_ID_DATA__REF_VALUE;
186*29396cd5SIan Rogers 		if (expr__parse(&data->ref.val, ctx, data->ref.metric_expr, 1)) {
187acf71b05SJiri Olsa 			pr_debug("%s failed to count\n", id);
188acf71b05SJiri Olsa 			return -1;
189acf71b05SJiri Olsa 		}
190acf71b05SJiri Olsa 		pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
191*29396cd5SIan Rogers 		break;
192*29396cd5SIan Rogers 	case EXPR_ID_DATA__REF_VALUE:
193*29396cd5SIan Rogers 		pr_debug2("lookup(%s): ref val %f metric name %s\n", id,
194*29396cd5SIan Rogers 			data->ref.val, data->ref.metric_name);
195*29396cd5SIan Rogers 		break;
196*29396cd5SIan Rogers 	default:
197*29396cd5SIan Rogers 		assert(0);  /* Unreachable. */
198acf71b05SJiri Olsa 	}
199acf71b05SJiri Olsa 
200acf71b05SJiri Olsa 	return 0;
201acf71b05SJiri Olsa }
202acf71b05SJiri Olsa 
2033fd29fa6SJiri Olsa void expr__del_id(struct expr_parse_ctx *ctx, const char *id)
2043fd29fa6SJiri Olsa {
2053fd29fa6SJiri Olsa 	struct expr_id_data *old_val = NULL;
2063fd29fa6SJiri Olsa 	char *old_key = NULL;
2073fd29fa6SJiri Olsa 
2083fd29fa6SJiri Olsa 	hashmap__delete(&ctx->ids, id,
2093fd29fa6SJiri Olsa 			(const void **)&old_key, (void **)&old_val);
2103fd29fa6SJiri Olsa 	free(old_key);
2113fd29fa6SJiri Olsa 	free(old_val);
2123fd29fa6SJiri Olsa }
2133fd29fa6SJiri Olsa 
214aecce63eSJiri Olsa void expr__ctx_init(struct expr_parse_ctx *ctx)
215576a65b6SJiri Olsa {
216ded80bdaSIan Rogers 	hashmap__init(&ctx->ids, key_hash, key_equal, NULL);
217ded80bdaSIan Rogers }
218ded80bdaSIan Rogers 
219ded80bdaSIan Rogers void expr__ctx_clear(struct expr_parse_ctx *ctx)
220ded80bdaSIan Rogers {
221ded80bdaSIan Rogers 	struct hashmap_entry *cur;
222ded80bdaSIan Rogers 	size_t bkt;
223ded80bdaSIan Rogers 
224ded80bdaSIan Rogers 	hashmap__for_each_entry((&ctx->ids), cur, bkt) {
225ded80bdaSIan Rogers 		free((char *)cur->key);
226ded80bdaSIan Rogers 		free(cur->value);
227ded80bdaSIan Rogers 	}
228ded80bdaSIan Rogers 	hashmap__clear(&ctx->ids);
229576a65b6SJiri Olsa }
23026226a97SJiri Olsa 
23126226a97SJiri Olsa static int
232aecce63eSJiri Olsa __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
2331e1a873dSKajol Jain 	      int start, int runtime)
23426226a97SJiri Olsa {
235871f9f59SJiri Olsa 	struct expr_scanner_ctx scanner_ctx = {
236871f9f59SJiri Olsa 		.start_token = start,
2371e1a873dSKajol Jain 		.runtime = runtime,
238871f9f59SJiri Olsa 	};
23926226a97SJiri Olsa 	YY_BUFFER_STATE buffer;
24026226a97SJiri Olsa 	void *scanner;
24126226a97SJiri Olsa 	int ret;
24226226a97SJiri Olsa 
243acf71b05SJiri Olsa 	pr_debug2("parsing metric: %s\n", expr);
244acf71b05SJiri Olsa 
245871f9f59SJiri Olsa 	ret = expr_lex_init_extra(&scanner_ctx, &scanner);
24626226a97SJiri Olsa 	if (ret)
24726226a97SJiri Olsa 		return ret;
24826226a97SJiri Olsa 
24926226a97SJiri Olsa 	buffer = expr__scan_string(expr, scanner);
25026226a97SJiri Olsa 
25126226a97SJiri Olsa #ifdef PARSER_DEBUG
25226226a97SJiri Olsa 	expr_debug = 1;
253e5e0e635SIan Rogers 	expr_set_debug(1, scanner);
25426226a97SJiri Olsa #endif
25526226a97SJiri Olsa 
25626226a97SJiri Olsa 	ret = expr_parse(val, ctx, scanner);
25726226a97SJiri Olsa 
25826226a97SJiri Olsa 	expr__flush_buffer(buffer, scanner);
25926226a97SJiri Olsa 	expr__delete_buffer(buffer, scanner);
26026226a97SJiri Olsa 	expr_lex_destroy(scanner);
26126226a97SJiri Olsa 	return ret;
26226226a97SJiri Olsa }
26326226a97SJiri Olsa 
264ded80bdaSIan Rogers int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
265ded80bdaSIan Rogers 		const char *expr, int runtime)
26626226a97SJiri Olsa {
2671e1a873dSKajol Jain 	return __expr__parse(final_val, ctx, expr, EXPR_PARSE, runtime) ? -1 : 0;
26826226a97SJiri Olsa }
26926226a97SJiri Olsa 
270ded80bdaSIan Rogers int expr__find_other(const char *expr, const char *one,
271ded80bdaSIan Rogers 		     struct expr_parse_ctx *ctx, int runtime)
27226226a97SJiri Olsa {
273ded80bdaSIan Rogers 	int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime);
27426226a97SJiri Olsa 
2753fd29fa6SJiri Olsa 	if (one)
2763fd29fa6SJiri Olsa 		expr__del_id(ctx, one);
27726226a97SJiri Olsa 
278ded80bdaSIan Rogers 	return ret;
27926226a97SJiri Olsa }
280*29396cd5SIan Rogers 
281*29396cd5SIan Rogers double expr_id_data__value(const struct expr_id_data *data)
282*29396cd5SIan Rogers {
283*29396cd5SIan Rogers 	if (data->kind == EXPR_ID_DATA__VALUE)
284*29396cd5SIan Rogers 		return data->val;
285*29396cd5SIan Rogers 	assert(data->kind == EXPR_ID_DATA__REF_VALUE);
286*29396cd5SIan Rogers 	return data->ref.val;
287*29396cd5SIan Rogers }
288*29396cd5SIan Rogers 
289*29396cd5SIan Rogers struct expr_id *expr_id_data__parent(struct expr_id_data *data)
290*29396cd5SIan Rogers {
291*29396cd5SIan Rogers 	assert(data->kind == EXPR_ID_DATA__PARENT);
292*29396cd5SIan Rogers 	return data->parent;
293*29396cd5SIan Rogers }
294