Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07516736 authored by Andi Kleen's avatar Andi Kleen Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Add a simple expression parser for JSON



Add a simple expression parser good enough to parse JSON relation
expressions. The parser is implemented using bison.

This is just intended as an simple parser for internal usage in the
event lists, not the beginning of a "perf scripting language"

v2: Use expr__ prefix instead of expr_
    Support multiple free variables for parser

Committer note:

The v2 patch had:

  %define api.pure full

In expr.y, that is a feature introduced in bison 2.7, to have reentrant
parsers, not using global variables, which would make tools/perf stop
building with the bison version shipped in older distros, so Andi
realised that the other parsers (e.g. parse-events.y) were using:

  %pure-parser

Which is present in older versions of bison and fits the bill.

I added:

  CFLAGS_expr-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w

To finally make it build, copying what was there for pmu-bison.o,
another parser.

Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/20170320201711.14142-8-andi@firstfloor.org


[ stdlib.h is needed in tests/expr.c for free() fixing build in systems such as ubuntu:16.04-x-s390 ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent a820e335
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ perf-y += cpumap.o
perf-y += stat.o
perf-y += event_update.o
perf-y += event-times.o
perf-y += expr.o
perf-y += backward-ring-buffer.o
perf-y += sdt.o
perf-y += is_printable_array.o
+4 −0
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@ static struct test generic_tests[] = {
		.desc = "Parse event definition strings",
		.func = test__parse_events,
	},
	{
		.desc = "Simple expression parser",
		.func = test__expr,
	},
	{
		.desc = "PERF_RECORD_* events & perf_sample fields",
		.func = test__PERF_RECORD,
+56 −0
Original line number Diff line number Diff line
#include "util/debug.h"
#include "util/expr.h"
#include "tests.h"
#include <stdlib.h>

static int test(struct parse_ctx *ctx, const char *e, double val2)
{
	double val;

	if (expr__parse(&val, ctx, &e))
		TEST_ASSERT_VAL("parse test failed", 0);
	TEST_ASSERT_VAL("unexpected value", val == val2);
	return 0;
}

int test__expr(int subtest __maybe_unused)
{
	const char *p;
	const char **other;
	double val;
	int ret;
	struct parse_ctx ctx;
	int num_other;

	expr__ctx_init(&ctx);
	expr__add_id(&ctx, "FOO", 1);
	expr__add_id(&ctx, "BAR", 2);

	ret = test(&ctx, "1+1", 2);
	ret |= test(&ctx, "FOO+BAR", 3);
	ret |= test(&ctx, "(BAR/2)%2", 1);
	ret |= test(&ctx, "1 - -4",  5);
	ret |= test(&ctx, "(FOO-1)*2 + (BAR/2)%2 - -4",  5);

	if (ret)
		return ret;

	p = "FOO/0";
	ret = expr__parse(&val, &ctx, &p);
	TEST_ASSERT_VAL("division by zero", ret == 1);

	p = "BAR/";
	ret = expr__parse(&val, &ctx, &p);
	TEST_ASSERT_VAL("missing operand", ret == 1);

	TEST_ASSERT_VAL("find other",
			expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", &other, &num_other) == 0);
	TEST_ASSERT_VAL("find other", num_other == 3);
	TEST_ASSERT_VAL("find other", !strcmp(other[0], "BAR"));
	TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ"));
	TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO"));
	TEST_ASSERT_VAL("find other", other[3] == NULL);
	free((void *)other);

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ int test__sample_parsing(int subtest);
int test__keep_tracking(int subtest);
int test__parse_no_sample_id_all(int subtest);
int test__dwarf_unwind(int subtest);
int test__expr(int subtest);
int test__hists_filter(int subtest);
int test__mmap_thread_lookup(int subtest);
int test__thread_mg_share(int subtest);
+6 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ libperf-y += mem-events.o
libperf-y += vsprintf.o
libperf-y += drv_configs.o
libperf-y += time-utils.o
libperf-y += expr-bison.o

libperf-$(CONFIG_LIBBPF) += bpf-loader.o
libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -142,6 +143,10 @@ $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
	$(call rule_mkdir)
	$(Q)$(call echo-cmd,bison)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $@ -p parse_events_

$(OUTPUT)util/expr-bison.c: util/expr.y
	$(call rule_mkdir)
	$(Q)$(call echo-cmd,bison)$(BISON) -v util/expr.y -d $(PARSER_DEBUG_BISON) -o $@ -p expr__

$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
	$(call rule_mkdir)
	$(Q)$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l
@@ -154,6 +159,7 @@ CFLAGS_parse-events-flex.o += -w
CFLAGS_pmu-flex.o           += -w
CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -w
CFLAGS_pmu-bison.o          += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
CFLAGS_expr-bison.o         += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w

$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
Loading