From: Sandeep Dasgupta <sdas...@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 <irog...@google.com> Signed-off-by: Ian Rogers <irog...@google.com> Signed-off-by: Sandeep Dasgupta <sdas...@google.com> --- .../pmu-events/topdown-parser/jsmn_extras.cpp | 199 ++++++++++++++++++ .../pmu-events/topdown-parser/jsmn_extras.h | 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 diff --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 diff --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