162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <stdbool.h>
362306a36Sopenharmony_ci#include <assert.h>
462306a36Sopenharmony_ci#include <errno.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <string.h>
762306a36Sopenharmony_ci#include "metricgroup.h"
862306a36Sopenharmony_ci#include "cpumap.h"
962306a36Sopenharmony_ci#include "cputopo.h"
1062306a36Sopenharmony_ci#include "debug.h"
1162306a36Sopenharmony_ci#include "evlist.h"
1262306a36Sopenharmony_ci#include "expr.h"
1362306a36Sopenharmony_ci#include <util/expr-bison.h>
1462306a36Sopenharmony_ci#include <util/expr-flex.h>
1562306a36Sopenharmony_ci#include "util/hashmap.h"
1662306a36Sopenharmony_ci#include "util/header.h"
1762306a36Sopenharmony_ci#include "util/pmu.h"
1862306a36Sopenharmony_ci#include "smt.h"
1962306a36Sopenharmony_ci#include "tsc.h"
2062306a36Sopenharmony_ci#include <api/fs/fs.h>
2162306a36Sopenharmony_ci#include <linux/err.h>
2262306a36Sopenharmony_ci#include <linux/kernel.h>
2362306a36Sopenharmony_ci#include <linux/zalloc.h>
2462306a36Sopenharmony_ci#include <ctype.h>
2562306a36Sopenharmony_ci#include <math.h>
2662306a36Sopenharmony_ci#include "pmu.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#ifdef PARSER_DEBUG
2962306a36Sopenharmony_ciextern int expr_debug;
3062306a36Sopenharmony_ci#endif
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct expr_id_data {
3362306a36Sopenharmony_ci	union {
3462306a36Sopenharmony_ci		struct {
3562306a36Sopenharmony_ci			double val;
3662306a36Sopenharmony_ci			int source_count;
3762306a36Sopenharmony_ci		} val;
3862306a36Sopenharmony_ci		struct {
3962306a36Sopenharmony_ci			double val;
4062306a36Sopenharmony_ci			const char *metric_name;
4162306a36Sopenharmony_ci			const char *metric_expr;
4262306a36Sopenharmony_ci		} ref;
4362306a36Sopenharmony_ci	};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	enum {
4662306a36Sopenharmony_ci		/* Holding a double value. */
4762306a36Sopenharmony_ci		EXPR_ID_DATA__VALUE,
4862306a36Sopenharmony_ci		/* Reference to another metric. */
4962306a36Sopenharmony_ci		EXPR_ID_DATA__REF,
5062306a36Sopenharmony_ci		/* A reference but the value has been computed. */
5162306a36Sopenharmony_ci		EXPR_ID_DATA__REF_VALUE,
5262306a36Sopenharmony_ci	} kind;
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic size_t key_hash(long key, void *ctx __maybe_unused)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	const char *str = (const char *)key;
5862306a36Sopenharmony_ci	size_t hash = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	while (*str != '\0') {
6162306a36Sopenharmony_ci		hash *= 31;
6262306a36Sopenharmony_ci		hash += *str;
6362306a36Sopenharmony_ci		str++;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	return hash;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic bool key_equal(long key1, long key2, void *ctx __maybe_unused)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return !strcmp((const char *)key1, (const char *)key2);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct hashmap *ids__new(void)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct hashmap *hash;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	hash = hashmap__new(key_hash, key_equal, NULL);
7862306a36Sopenharmony_ci	if (IS_ERR(hash))
7962306a36Sopenharmony_ci		return NULL;
8062306a36Sopenharmony_ci	return hash;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_civoid ids__free(struct hashmap *ids)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct hashmap_entry *cur;
8662306a36Sopenharmony_ci	size_t bkt;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (ids == NULL)
8962306a36Sopenharmony_ci		return;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	hashmap__for_each_entry(ids, cur, bkt) {
9262306a36Sopenharmony_ci		zfree(&cur->pkey);
9362306a36Sopenharmony_ci		zfree(&cur->pvalue);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	hashmap__free(ids);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint ids__insert(struct hashmap *ids, const char *id)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
10262306a36Sopenharmony_ci	char *old_key = NULL;
10362306a36Sopenharmony_ci	int ret;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ret = hashmap__set(ids, id, data_ptr, &old_key, &old_data);
10662306a36Sopenharmony_ci	if (ret)
10762306a36Sopenharmony_ci		free(data_ptr);
10862306a36Sopenharmony_ci	free(old_key);
10962306a36Sopenharmony_ci	free(old_data);
11062306a36Sopenharmony_ci	return ret;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistruct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	size_t bkt;
11662306a36Sopenharmony_ci	struct hashmap_entry *cur;
11762306a36Sopenharmony_ci	int ret;
11862306a36Sopenharmony_ci	struct expr_id_data *old_data = NULL;
11962306a36Sopenharmony_ci	char *old_key = NULL;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (!ids1)
12262306a36Sopenharmony_ci		return ids2;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!ids2)
12562306a36Sopenharmony_ci		return ids1;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (hashmap__size(ids1) <  hashmap__size(ids2)) {
12862306a36Sopenharmony_ci		struct hashmap *tmp = ids1;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		ids1 = ids2;
13162306a36Sopenharmony_ci		ids2 = tmp;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci	hashmap__for_each_entry(ids2, cur, bkt) {
13462306a36Sopenharmony_ci		ret = hashmap__set(ids1, cur->key, cur->value, &old_key, &old_data);
13562306a36Sopenharmony_ci		free(old_key);
13662306a36Sopenharmony_ci		free(old_data);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		if (ret) {
13962306a36Sopenharmony_ci			hashmap__free(ids1);
14062306a36Sopenharmony_ci			hashmap__free(ids2);
14162306a36Sopenharmony_ci			return NULL;
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	hashmap__free(ids2);
14562306a36Sopenharmony_ci	return ids1;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* Caller must make sure id is allocated */
14962306a36Sopenharmony_ciint expr__add_id(struct expr_parse_ctx *ctx, const char *id)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return ids__insert(ctx->ids, id);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/* Caller must make sure id is allocated */
15562306a36Sopenharmony_ciint expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	return expr__add_id_val_source_count(ctx, id, val, /*source_count=*/1);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* Caller must make sure id is allocated */
16162306a36Sopenharmony_ciint expr__add_id_val_source_count(struct expr_parse_ctx *ctx, const char *id,
16262306a36Sopenharmony_ci				  double val, int source_count)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
16562306a36Sopenharmony_ci	char *old_key = NULL;
16662306a36Sopenharmony_ci	int ret;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	data_ptr = malloc(sizeof(*data_ptr));
16962306a36Sopenharmony_ci	if (!data_ptr)
17062306a36Sopenharmony_ci		return -ENOMEM;
17162306a36Sopenharmony_ci	data_ptr->val.val = val;
17262306a36Sopenharmony_ci	data_ptr->val.source_count = source_count;
17362306a36Sopenharmony_ci	data_ptr->kind = EXPR_ID_DATA__VALUE;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	ret = hashmap__set(ctx->ids, id, data_ptr, &old_key, &old_data);
17662306a36Sopenharmony_ci	if (ret)
17762306a36Sopenharmony_ci		free(data_ptr);
17862306a36Sopenharmony_ci	free(old_key);
17962306a36Sopenharmony_ci	free(old_data);
18062306a36Sopenharmony_ci	return ret;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ciint expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct expr_id_data *data_ptr = NULL, *old_data = NULL;
18662306a36Sopenharmony_ci	char *old_key = NULL;
18762306a36Sopenharmony_ci	char *name;
18862306a36Sopenharmony_ci	int ret;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	data_ptr = zalloc(sizeof(*data_ptr));
19162306a36Sopenharmony_ci	if (!data_ptr)
19262306a36Sopenharmony_ci		return -ENOMEM;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	name = strdup(ref->metric_name);
19562306a36Sopenharmony_ci	if (!name) {
19662306a36Sopenharmony_ci		free(data_ptr);
19762306a36Sopenharmony_ci		return -ENOMEM;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/*
20162306a36Sopenharmony_ci	 * Intentionally passing just const char pointers,
20262306a36Sopenharmony_ci	 * originally from 'struct pmu_event' object.
20362306a36Sopenharmony_ci	 * We don't need to change them, so there's no
20462306a36Sopenharmony_ci	 * need to create our own copy.
20562306a36Sopenharmony_ci	 */
20662306a36Sopenharmony_ci	data_ptr->ref.metric_name = ref->metric_name;
20762306a36Sopenharmony_ci	data_ptr->ref.metric_expr = ref->metric_expr;
20862306a36Sopenharmony_ci	data_ptr->kind = EXPR_ID_DATA__REF;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ret = hashmap__set(ctx->ids, name, data_ptr, &old_key, &old_data);
21162306a36Sopenharmony_ci	if (ret)
21262306a36Sopenharmony_ci		free(data_ptr);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	pr_debug2("adding ref metric %s: %s\n",
21562306a36Sopenharmony_ci		  ref->metric_name, ref->metric_expr);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	free(old_key);
21862306a36Sopenharmony_ci	free(old_data);
21962306a36Sopenharmony_ci	return ret;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciint expr__get_id(struct expr_parse_ctx *ctx, const char *id,
22362306a36Sopenharmony_ci		 struct expr_id_data **data)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	return hashmap__find(ctx->ids, id, data) ? 0 : -1;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cibool expr__subset_of_ids(struct expr_parse_ctx *haystack,
22962306a36Sopenharmony_ci			 struct expr_parse_ctx *needles)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct hashmap_entry *cur;
23262306a36Sopenharmony_ci	size_t bkt;
23362306a36Sopenharmony_ci	struct expr_id_data *data;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	hashmap__for_each_entry(needles->ids, cur, bkt) {
23662306a36Sopenharmony_ci		if (expr__get_id(haystack, cur->pkey, &data))
23762306a36Sopenharmony_ci			return false;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci	return true;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciint expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
24462306a36Sopenharmony_ci		     struct expr_id_data **datap)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct expr_id_data *data;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (expr__get_id(ctx, id, datap) || !*datap) {
24962306a36Sopenharmony_ci		pr_debug("%s not found\n", id);
25062306a36Sopenharmony_ci		return -1;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	data = *datap;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	switch (data->kind) {
25662306a36Sopenharmony_ci	case EXPR_ID_DATA__VALUE:
25762306a36Sopenharmony_ci		pr_debug2("lookup(%s): val %f\n", id, data->val.val);
25862306a36Sopenharmony_ci		break;
25962306a36Sopenharmony_ci	case EXPR_ID_DATA__REF:
26062306a36Sopenharmony_ci		pr_debug2("lookup(%s): ref metric name %s\n", id,
26162306a36Sopenharmony_ci			data->ref.metric_name);
26262306a36Sopenharmony_ci		pr_debug("processing metric: %s ENTRY\n", id);
26362306a36Sopenharmony_ci		data->kind = EXPR_ID_DATA__REF_VALUE;
26462306a36Sopenharmony_ci		if (expr__parse(&data->ref.val, ctx, data->ref.metric_expr)) {
26562306a36Sopenharmony_ci			pr_debug("%s failed to count\n", id);
26662306a36Sopenharmony_ci			return -1;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci		pr_debug("processing metric: %s EXIT: %f\n", id, data->ref.val);
26962306a36Sopenharmony_ci		break;
27062306a36Sopenharmony_ci	case EXPR_ID_DATA__REF_VALUE:
27162306a36Sopenharmony_ci		pr_debug2("lookup(%s): ref val %f metric name %s\n", id,
27262306a36Sopenharmony_ci			data->ref.val, data->ref.metric_name);
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	default:
27562306a36Sopenharmony_ci		assert(0);  /* Unreachable. */
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_civoid expr__del_id(struct expr_parse_ctx *ctx, const char *id)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct expr_id_data *old_val = NULL;
28462306a36Sopenharmony_ci	char *old_key = NULL;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	hashmap__delete(ctx->ids, id, &old_key, &old_val);
28762306a36Sopenharmony_ci	free(old_key);
28862306a36Sopenharmony_ci	free(old_val);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistruct expr_parse_ctx *expr__ctx_new(void)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct expr_parse_ctx *ctx;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	ctx = malloc(sizeof(struct expr_parse_ctx));
29662306a36Sopenharmony_ci	if (!ctx)
29762306a36Sopenharmony_ci		return NULL;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	ctx->ids = hashmap__new(key_hash, key_equal, NULL);
30062306a36Sopenharmony_ci	if (IS_ERR(ctx->ids)) {
30162306a36Sopenharmony_ci		free(ctx);
30262306a36Sopenharmony_ci		return NULL;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	ctx->sctx.user_requested_cpu_list = NULL;
30562306a36Sopenharmony_ci	ctx->sctx.runtime = 0;
30662306a36Sopenharmony_ci	ctx->sctx.system_wide = false;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return ctx;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_civoid expr__ctx_clear(struct expr_parse_ctx *ctx)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct hashmap_entry *cur;
31462306a36Sopenharmony_ci	size_t bkt;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	hashmap__for_each_entry(ctx->ids, cur, bkt) {
31762306a36Sopenharmony_ci		zfree(&cur->pkey);
31862306a36Sopenharmony_ci		zfree(&cur->pvalue);
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci	hashmap__clear(ctx->ids);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_civoid expr__ctx_free(struct expr_parse_ctx *ctx)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct hashmap_entry *cur;
32662306a36Sopenharmony_ci	size_t bkt;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!ctx)
32962306a36Sopenharmony_ci		return;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	zfree(&ctx->sctx.user_requested_cpu_list);
33262306a36Sopenharmony_ci	hashmap__for_each_entry(ctx->ids, cur, bkt) {
33362306a36Sopenharmony_ci		zfree(&cur->pkey);
33462306a36Sopenharmony_ci		zfree(&cur->pvalue);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci	hashmap__free(ctx->ids);
33762306a36Sopenharmony_ci	free(ctx);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int
34162306a36Sopenharmony_ci__expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr,
34262306a36Sopenharmony_ci	      bool compute_ids)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	YY_BUFFER_STATE buffer;
34562306a36Sopenharmony_ci	void *scanner;
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	pr_debug2("parsing metric: %s\n", expr);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ret = expr_lex_init_extra(&ctx->sctx, &scanner);
35162306a36Sopenharmony_ci	if (ret)
35262306a36Sopenharmony_ci		return ret;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	buffer = expr__scan_string(expr, scanner);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci#ifdef PARSER_DEBUG
35762306a36Sopenharmony_ci	expr_debug = 1;
35862306a36Sopenharmony_ci	expr_set_debug(1, scanner);
35962306a36Sopenharmony_ci#endif
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	ret = expr_parse(val, ctx, compute_ids, scanner);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	expr__flush_buffer(buffer, scanner);
36462306a36Sopenharmony_ci	expr__delete_buffer(buffer, scanner);
36562306a36Sopenharmony_ci	expr_lex_destroy(scanner);
36662306a36Sopenharmony_ci	return ret;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciint expr__parse(double *final_val, struct expr_parse_ctx *ctx,
37062306a36Sopenharmony_ci		const char *expr)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	return __expr__parse(final_val, ctx, expr, /*compute_ids=*/false) ? -1 : 0;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ciint expr__find_ids(const char *expr, const char *one,
37662306a36Sopenharmony_ci		   struct expr_parse_ctx *ctx)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	int ret = __expr__parse(NULL, ctx, expr, /*compute_ids=*/true);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (one)
38162306a36Sopenharmony_ci		expr__del_id(ctx, one);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return ret;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cidouble expr_id_data__value(const struct expr_id_data *data)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	if (data->kind == EXPR_ID_DATA__VALUE)
38962306a36Sopenharmony_ci		return data->val.val;
39062306a36Sopenharmony_ci	assert(data->kind == EXPR_ID_DATA__REF_VALUE);
39162306a36Sopenharmony_ci	return data->ref.val;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cidouble expr_id_data__source_count(const struct expr_id_data *data)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	assert(data->kind == EXPR_ID_DATA__VALUE);
39762306a36Sopenharmony_ci	return data->val.source_count;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
40162306a36Sopenharmony_cidouble arch_get_tsc_freq(void)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	return 0.0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci#endif
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic double has_pmem(void)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	static bool has_pmem, cached;
41062306a36Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
41162306a36Sopenharmony_ci	char path[PATH_MAX];
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!cached) {
41462306a36Sopenharmony_ci		snprintf(path, sizeof(path), "%s/firmware/acpi/tables/NFIT", sysfs);
41562306a36Sopenharmony_ci		has_pmem = access(path, F_OK) == 0;
41662306a36Sopenharmony_ci		cached = true;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	return has_pmem ? 1.0 : 0.0;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cidouble expr__get_literal(const char *literal, const struct expr_scanner_ctx *ctx)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	const struct cpu_topology *topology;
42462306a36Sopenharmony_ci	double result = NAN;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (!strcmp("#num_cpus", literal)) {
42762306a36Sopenharmony_ci		result = cpu__max_present_cpu().cpu;
42862306a36Sopenharmony_ci		goto out;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci	if (!strcmp("#num_cpus_online", literal)) {
43162306a36Sopenharmony_ci		struct perf_cpu_map *online = cpu_map__online();
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		if (online)
43462306a36Sopenharmony_ci			result = perf_cpu_map__nr(online);
43562306a36Sopenharmony_ci		goto out;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (!strcasecmp("#system_tsc_freq", literal)) {
43962306a36Sopenharmony_ci		result = arch_get_tsc_freq();
44062306a36Sopenharmony_ci		goto out;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/*
44462306a36Sopenharmony_ci	 * Assume that topology strings are consistent, such as CPUs "0-1"
44562306a36Sopenharmony_ci	 * wouldn't be listed as "0,1", and so after deduplication the number of
44662306a36Sopenharmony_ci	 * these strings gives an indication of the number of packages, dies,
44762306a36Sopenharmony_ci	 * etc.
44862306a36Sopenharmony_ci	 */
44962306a36Sopenharmony_ci	if (!strcasecmp("#smt_on", literal)) {
45062306a36Sopenharmony_ci		result = smt_on() ? 1.0 : 0.0;
45162306a36Sopenharmony_ci		goto out;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci	if (!strcmp("#core_wide", literal)) {
45462306a36Sopenharmony_ci		result = core_wide(ctx->system_wide, ctx->user_requested_cpu_list)
45562306a36Sopenharmony_ci			? 1.0 : 0.0;
45662306a36Sopenharmony_ci		goto out;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci	if (!strcmp("#num_packages", literal)) {
45962306a36Sopenharmony_ci		topology = online_topology();
46062306a36Sopenharmony_ci		result = topology->package_cpus_lists;
46162306a36Sopenharmony_ci		goto out;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	if (!strcmp("#num_dies", literal)) {
46462306a36Sopenharmony_ci		topology = online_topology();
46562306a36Sopenharmony_ci		result = topology->die_cpus_lists;
46662306a36Sopenharmony_ci		goto out;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci	if (!strcmp("#num_cores", literal)) {
46962306a36Sopenharmony_ci		topology = online_topology();
47062306a36Sopenharmony_ci		result = topology->core_cpus_lists;
47162306a36Sopenharmony_ci		goto out;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	if (!strcmp("#slots", literal)) {
47462306a36Sopenharmony_ci		result = perf_pmu__cpu_slots_per_cycle();
47562306a36Sopenharmony_ci		goto out;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	if (!strcmp("#has_pmem", literal)) {
47862306a36Sopenharmony_ci		result = has_pmem();
47962306a36Sopenharmony_ci		goto out;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	pr_err("Unrecognized literal '%s'", literal);
48362306a36Sopenharmony_ciout:
48462306a36Sopenharmony_ci	pr_debug2("literal: %s = %f\n", literal, result);
48562306a36Sopenharmony_ci	return result;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/* Does the event 'id' parse? Determine via ctx->ids if possible. */
48962306a36Sopenharmony_cidouble expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const char *id)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	struct evlist *tmp;
49262306a36Sopenharmony_ci	double ret;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (hashmap__find(ctx->ids, id, /*value=*/NULL))
49562306a36Sopenharmony_ci		return 1.0;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (!compute_ids)
49862306a36Sopenharmony_ci		return 0.0;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	tmp = evlist__new();
50162306a36Sopenharmony_ci	if (!tmp)
50262306a36Sopenharmony_ci		return NAN;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (strchr(id, '@')) {
50562306a36Sopenharmony_ci		char *tmp_id, *p;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		tmp_id = strdup(id);
50862306a36Sopenharmony_ci		if (!tmp_id) {
50962306a36Sopenharmony_ci			ret = NAN;
51062306a36Sopenharmony_ci			goto out;
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci		p = strchr(tmp_id, '@');
51362306a36Sopenharmony_ci		*p = '/';
51462306a36Sopenharmony_ci		p = strrchr(tmp_id, '@');
51562306a36Sopenharmony_ci		*p = '/';
51662306a36Sopenharmony_ci		ret = parse_event(tmp, tmp_id) ? 0 : 1;
51762306a36Sopenharmony_ci		free(tmp_id);
51862306a36Sopenharmony_ci	} else {
51962306a36Sopenharmony_ci		ret = parse_event(tmp, id) ? 0 : 1;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ciout:
52262306a36Sopenharmony_ci	evlist__delete(tmp);
52362306a36Sopenharmony_ci	return ret;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cidouble expr__strcmp_cpuid_str(const struct expr_parse_ctx *ctx __maybe_unused,
52762306a36Sopenharmony_ci		       bool compute_ids __maybe_unused, const char *test_id)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	double ret;
53062306a36Sopenharmony_ci	struct perf_pmu *pmu = pmu__find_core_pmu();
53162306a36Sopenharmony_ci	char *cpuid = perf_pmu__getcpuid(pmu);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (!cpuid)
53462306a36Sopenharmony_ci		return NAN;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	ret = !strcmp_cpuid_str(test_id, cpuid);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	free(cpuid);
53962306a36Sopenharmony_ci	return ret;
54062306a36Sopenharmony_ci}
541