From: Ian Rogers <irogers@google.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@redhat.com>, Namhyung Kim <namhyung@kernel.org>,
linux-kernel@vger.kernel.org, Andi Kleen <ak@linux.intel.com>,
Jin Yao <yao.jin@linux.intel.com>,
John Garry <john.garry@huawei.com>, Paul Clarke <pc@us.ibm.com>,
kajoljain <kjain@linux.ibm.com>
Cc: Stephane Eranian <eranian@google.com>,
Sandeep Dasgupta <sdasgup@google.com>,
linux-perf-users@vger.kernel.org, Ian Rogers <irogers@google.com>
Subject: [RFC PATCH 04/12] perf topdown-parser: Add a json file reader.
Date: Tue, 10 Nov 2020 02:03:38 -0800
Message-ID: <20201110100346.2527031-5-irogers@google.com> (raw)
In-Reply-To: <20201110100346.2527031-1-irogers@google.com>
From: Sandeep Dasgupta <sdasgup@google.com>
Wrap jsmn as a "C" library. Add some utilities for working with tokens
and to read a vector of tokens.
Co-authored-by: Ian Rogers <irogers@google.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Sandeep Dasgupta <sdasgup@google.com>
---
| 199 ++++++++++++++++++
| 42 ++++
2 files changed, 241 insertions(+)
create mode 100644 tools/perf/pmu-events/topdown-parser/jsmn_extras.cpp
create mode 100644 tools/perf/pmu-events/topdown-parser/jsmn_extras.h
--git a/tools/perf/pmu-events/topdown-parser/jsmn_extras.cpp b/tools/perf/pmu-events/topdown-parser/jsmn_extras.cpp
new file mode 100644
index 000000000000..83a15b636378
--- /dev/null
+++ b/tools/perf/pmu-events/topdown-parser/jsmn_extras.cpp
@@ -0,0 +1,199 @@
+#include "jsmn_extras.h"
+
+#include <cassert>
+#include <cstring>
+#include <functional>
+#include <memory>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "logging.h"
+
+namespace topdown_parser
+{
+int jsoneq(const char *json, const jsmntok_t *tok, const char *s)
+{
+ if (tok->type == JSMN_STRING &&
+ static_cast<int>(strlen(s)) == tok->end - tok->start &&
+ strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+int get_primitive(const char *js, const jsmntok_t *t, int i,
+ std::string *retval)
+{
+ if (t[i].type != JSMN_STRING && t[i].type != JSMN_PRIMITIVE) {
+ assert(0);
+ }
+ const jsmntok_t *g = t + i;
+ (*retval) = std::string(js + g->start, g->end - g->start);
+ return i;
+}
+
+// Parse the following pattern of key-values
+// A:B
+int get_key_val(const char *js, const jsmntok_t *t, int i,
+ std::pair<std::string, std::string> *P)
+{
+ assert(t[i].type == JSMN_STRING);
+ i = get_primitive(js, t, i, &((*P).first));
+
+ i++;
+ i = get_primitive(js, t, i, &((*P).second));
+
+ return i;
+}
+
+int get_array_of_primitives(const char *js, const jsmntok_t *t, int i,
+ std::vector<std::string> *V)
+{
+ int j;
+ if (t[i].type != JSMN_ARRAY) {
+ assert(0);
+ }
+ int size = t[i].size;
+ if (size == 0) {
+ return i;
+ }
+
+ i++;
+ std::string retval;
+
+ for (j = 0; j < size - 1; j++) {
+ i = get_primitive(js, t, i, &retval);
+ (*V).push_back(retval);
+ i++;
+ }
+ i = get_primitive(js, t, i, &retval);
+ (*V).push_back(retval);
+
+ return i;
+}
+
+int get_struct(const char *js, const jsmntok_t *t, int i,
+ std::map<std::string, std::string> *data)
+{
+ int j;
+ if (t[i].type != JSMN_OBJECT) {
+ assert(0);
+ }
+
+ int size = t[i].size;
+ i++;
+
+ for (j = 0; j < size - 2; j += 2) {
+ std::pair<std::string, std::string> P;
+ i = get_key_val(js, t, i, &P);
+ (*data).insert(P);
+ i++;
+ }
+ std::pair<std::string, std::string> P;
+ i = get_key_val(js, t, i, &P);
+ (*data).insert(P);
+ return i;
+}
+
+int get_struct_of_array(
+ const char *js, const jsmntok_t *t, int i,
+ std::unordered_map<std::string, std::vector<std::string> > *data)
+{
+ if (t[i].type != JSMN_OBJECT) {
+ assert(0);
+ }
+
+ int size = t[i].size;
+ i++;
+
+ std::string key;
+ for (int j = 0; j < size - 2; j += 2) {
+ i = get_primitive(js, t, i, &key);
+ i++;
+
+ i = get_array_of_primitives(js, t, i, &((*data)[key]));
+ i++;
+ }
+ i = get_primitive(js, t, i, &key);
+ i++;
+ i = get_array_of_primitives(js, t, i, &((*data)[key]));
+ return i;
+}
+
+/**
+ * ParseJson parses a json file file 'fname' and delegate the processing of the
+ * parsed model to an external callback function 'callback' provided by the
+ * clients of the function.
+ *
+ * The clients using the following routine are:
+ * 1. ReadEventInfoFromJson: Parsing the event encoding json file for each CPU
+ * as downloaded from https://download.01.org/perfmon/
+ * 2. ReadConfig: Parsing the configuration.json file, which specifies the
+ * parameters for the topdown_parser tool.
+ */
+int ParseJson(const char *fname,
+ void (*callback)(const char *, const jsmntok_t *, int, void *),
+ void *metainfo)
+{
+ // Read the file fully into js.
+ int fd = open(fname, O_RDONLY);
+ if (fd == -1) {
+ ERROR("Failed to open '" << fname << "': " << strerror(errno));
+ return 1;
+ }
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) == -1) {
+ ERROR("Failed to stat '" << fname << "': " << strerror(errno));
+ close(fd);
+ return 2;
+ }
+
+ std::unique_ptr<char[]> js(new char[statbuf.st_size]);
+ if (read(fd, js.get(), statbuf.st_size) < 0) {
+ ERROR("Failed to read '" << fname << "': " << strerror(errno));
+ close(fd);
+ return 3;
+ }
+ close(fd);
+
+ // Prepare parser.
+ jsmn_parser p;
+ jsmn_init(&p);
+
+ // Allocate some tokens as a start then iterate until resizing is
+ // unnecessary.
+ std::vector<jsmntok_t> tok;
+ tok.resize(32);
+
+ jsmnerr_t r;
+ do {
+ r = jsmn_parse(&p, js.get(), statbuf.st_size, tok.data(),
+ tok.size());
+ if (r == JSMN_ERROR_NOMEM) {
+ tok.resize(tok.size() * 2);
+ }
+ } while (r == JSMN_ERROR_NOMEM);
+
+ switch (r) {
+ default:
+ ERROR("Json parse error " << r << " in '" << fname << "' at "
+ << p.pos);
+ return 4;
+ case JSMN_ERROR_INVAL:
+ ERROR("Invalid character in '" << fname << "' at " << p.pos);
+ return 5;
+ case JSMN_ERROR_PART:
+ ERROR("Incomplete json packet in '" << fname << "' at "
+ << p.pos);
+ return 6;
+ case JSMN_SUCCESS:
+ break;
+ }
+ (*callback)(js.get(), tok.data(), p.toknext, metainfo);
+ return 0;
+}
+
+} // namespace topdown_parser
--git a/tools/perf/pmu-events/topdown-parser/jsmn_extras.h b/tools/perf/pmu-events/topdown-parser/jsmn_extras.h
new file mode 100644
index 000000000000..b6721e50f064
--- /dev/null
+++ b/tools/perf/pmu-events/topdown-parser/jsmn_extras.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+// --------------------------------------------------
+// File: jsmn_extras.h
+// --------------------------------------------------
+//
+
+// The header provides additional helpers based on the jsmn library.
+
+#ifndef JSMN_EXTRAS_H_
+#define JSMN_EXTRAS_H_
+
+#include <cstdlib>
+extern "C" {
+#include "../jsmn.h"
+}
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace topdown_parser
+{
+int jsoneq(const char *json, const jsmntok_t *tok, const char *s);
+int get_primitive(const char *js, const jsmntok_t *t, int i,
+ std::string *retval);
+int get_key_val(const char *js, const jsmntok_t *t, int i,
+ std::pair<std::string, std::string> *P);
+int get_array_of_primitives(const char *js, const jsmntok_t *t, int i,
+ std::vector<std::string> *V);
+int get_struct(const char *js, const jsmntok_t *t, int i,
+ std::map<std::string, std::string> *data);
+int get_struct_of_array(
+ const char *js, const jsmntok_t *t, int i,
+ std::unordered_map<std::string, std::vector<std::string> > *data);
+int ParseJson(const char *fname,
+ void (*callback)(const char *, const jsmntok_t *, int, void *),
+ void *metainfo);
+
+} // namespace topdown_parser
+
+#endif // JSMN_EXTRAS_H_
--
2.29.2.222.g5d2a92d10f8-goog
next prev parent reply index
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-10 10:03 [RFC PATCH 00/12] Topdown parser Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 01/12] perf topdown-parser: Add a simple logging API Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 02/12] perf topdown-parser: Add utility functions Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 03/12] perf topdown-paser: Add a CSV file reader Ian Rogers
2020-11-10 10:03 ` Ian Rogers [this message]
2020-11-10 10:03 ` [RFC PATCH 05/12] perf topdown-parser: Add a configuration Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 06/12] perf topdown-parser: Interface for TMA_Metrics.csv Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 07/12] perf topdown-parser: Metric expression parser Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 08/12] perf topdown-parser: Add event interface Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 09/12] perf topdown-paser: Add code generation API Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 10/12] perf topdown-parser: Add json metric code generation Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 11/12] perf topdown-parser: Main driver Ian Rogers
2020-11-10 10:03 ` [RFC PATCH 12/12] perf pmu-events: Topdown parser tool Ian Rogers
2020-11-11 21:46 ` [RFC PATCH 00/12] Topdown parser Andi Kleen
[not found] ` <CAP-5=fXedJEZcYhxmPAzRVx5kdW2YA71Ks3BycqurAHydtXh8A@mail.gmail.com>
2020-11-12 3:10 ` Andi Kleen
[not found] ` <CAP-5=fUDOLzfpuJNjk_D6KrAGMNXKXOFKfVi9O7qXRDdP_4Rpg@mail.gmail.com>
2020-11-12 6:35 ` Andi Kleen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201110100346.2527031-5-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=ak@linux.intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=eranian@google.com \
--cc=john.garry@huawei.com \
--cc=jolsa@redhat.com \
--cc=kjain@linux.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=pc@us.ibm.com \
--cc=peterz@infradead.org \
--cc=sdasgup@google.com \
--cc=yao.jin@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Linux-perf-users Archive on lore.kernel.org
Archives are clonable:
git clone --mirror https://lore.kernel.org/linux-perf-users/0 linux-perf-users/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 linux-perf-users linux-perf-users/ https://lore.kernel.org/linux-perf-users \
linux-perf-users@vger.kernel.org
public-inbox-index linux-perf-users
Example config snippet for mirrors
Newsgroup available over NNTP:
nntp://nntp.lore.kernel.org/org.kernel.vger.linux-perf-users
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git