Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp3871036pxb; Tue, 10 Nov 2020 02:07:29 -0800 (PST) X-Google-Smtp-Source: ABdhPJx56EsHDl8RkM8w+lxAFcUuKXtwu/qdY6kO3yEdnMa8rLEPg5mMO96Q+hA6LswjqwTPEbrS X-Received: by 2002:a17:906:b852:: with SMTP id ga18mr20172514ejb.80.1605002849057; Tue, 10 Nov 2020 02:07:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605002849; cv=none; d=google.com; s=arc-20160816; b=DY4hmui42mtNs+gKm4Edv6WvczKg4mAesHVGFTH34mD5U8/1JOWIpQC/qBHgKDpjsp BnO/3WksQKkRSHJohvquKTi4o/zkitaTbZPe4udT52ROwfs3yxIAv9q9d3oR1i1Sc2r4 /Meh+35MLy3AMHcCmFRK/enXhHBf2rBRU8zERUOVvoBSxfezAKM1Fvsn267UAEWZgS+F MB8QbZXJNT7gycF6JEDNJlBS84BEtvDk+928bDgQo5zZ8oefsE3g4/I5Ss9S3zncIXFz TvuYRhe6JhVADZcRsCHSY7ufAnHQAn9B+ss9tRuHRgXeFbCx69Kn1bJIsh+2CZbcmI3b WFvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:sender:dkim-signature; bh=ArCbrSx70dCIk7ufmqy+hBV5Cv+6h8puV2QoRSi5mlw=; b=YbubNaXv1Gp8biubg0wJzsaCP/jlHKMfjfiDu+Vh7h8VzCfCMByF8hHajOr1MX68Su 5tXC35Ia7HmBq0Mb9C1n75ll+tIZAlV5zzUxgBy/1o2hoW7ee8uscfk6nF9QH1JvtNCi Y8H22EZxId93Fq0ToAyDtsDjHl8jBqpnSup2m9hK9tmYfo3adlT0hiMtVVlERyY/BOFa e1WeZK5RWNeDxLcqXAGT/cpHVmnMsyMmNqo+eJthIkqyrXhBVlcvIrjp6L3ZTpfr+Kf0 uNCdvNUiL3QigFVO+5hOSgU9v5/E+YaHJ/ULjYngL1vTL1C3rHugBiZyBwSm3BkHxyrD 9s6A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=k5Gj6viw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v8si8150303eju.136.2020.11.10.02.07.04; Tue, 10 Nov 2020 02:07:29 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=k5Gj6viw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731114AbgKJKEH (ORCPT + 99 others); Tue, 10 Nov 2020 05:04:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47400 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730824AbgKJKEG (ORCPT ); Tue, 10 Nov 2020 05:04:06 -0500 Received: from mail-qv1-xf49.google.com (mail-qv1-xf49.google.com [IPv6:2607:f8b0:4864:20::f49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B8DCBC0613CF for ; Tue, 10 Nov 2020 02:04:05 -0800 (PST) Received: by mail-qv1-xf49.google.com with SMTP id s5so3939755qvm.0 for ; Tue, 10 Nov 2020 02:04:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=ArCbrSx70dCIk7ufmqy+hBV5Cv+6h8puV2QoRSi5mlw=; b=k5Gj6viwYpUog6IR8+XtFPi7XRodJlD4YByxU8dYAz57J8ziGXu3rX6DyoWFDnQsb6 RGZv6PJoLsD7+HEgGqXUncJbIoT+x8IqMLjMGCxHJIB8QxmbYbxDrMwqm9uWGL710H1S HHNoY0lK+okOJ1PeSDqqBVJTNUg/WrB8c0iZS8BZ+0CYkvMsAkb1hT0/NcTCCyjtpECy XYguMACE8Rw1LJGokKat44UUHEUVRBrkdj/MoC+QF46+JtDrQa0xNmtnyKtsM0IcP0uX CIosrUSpQzDIA388XnEuoKUrDY685Wwy7FnAoeTZ+4Huc2ZA9F4p7dN+NmEd8ayxWj+u 3mLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ArCbrSx70dCIk7ufmqy+hBV5Cv+6h8puV2QoRSi5mlw=; b=BRwchv3ps0x1yayhyE77ILaSiqUzMcGfG88Fm7KngBWZPuzmQtoNn++Faw6cUsEMch po8mH6S2bOZc881yEJmWQwVnzA67AHNs8MWQZnM9Xtv6R6Bv+4cLfSeLix6PiPFCwnEM T174jPFd5Aqp4B775KEUKttxDlyVnQpYVNPhoRN6S+NFhnJPm4iKY1E+f0nfCapw/oAX sErqFx8Goc7phqwTuybY89Ae1vqXUHqnRmq2Pjb2y61EwdRo1cOgykSOy1KJRIqdU9iJ bSWFp/vmipmnj1NH35j1TEeXbT+BwPrYweCGNP15tJZX78eQekxBF8M60+j1kdnYVfzq I4NQ== X-Gm-Message-State: AOAM531bHzv4SnCHF+7tNieAfugenyy8AB2J8H8PJMnUDKnMucW5TYX9 1+VxoXyQIKeqzZ54is7fXgtZqgwbu/bz Sender: "irogers via sendgmr" X-Received: from irogers.svl.corp.google.com ([2620:15c:2cd:2:f693:9fff:fef4:4583]) (user=irogers job=sendgmr) by 2002:a0c:c18a:: with SMTP id n10mr19061238qvh.54.1605002644810; Tue, 10 Nov 2020 02:04:04 -0800 (PST) Date: Tue, 10 Nov 2020 02:03:38 -0800 In-Reply-To: <20201110100346.2527031-1-irogers@google.com> Message-Id: <20201110100346.2527031-5-irogers@google.com> Mime-Version: 1.0 References: <20201110100346.2527031-1-irogers@google.com> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog Subject: [RFC PATCH 04/12] perf topdown-parser: Add a json file reader. From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , linux-kernel@vger.kernel.org, Andi Kleen , Jin Yao , John Garry , Paul Clarke , kajoljain Cc: Stephane Eranian , Sandeep Dasgupta , linux-perf-users@vger.kernel.org, Ian Rogers Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sandeep Dasgupta 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 Signed-off-by: Ian Rogers Signed-off-by: Sandeep Dasgupta --- .../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 +#include +#include +#include + +#include +#include +#include +#include + +#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(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 *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 *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 *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 P; + i = get_key_val(js, t, i, &P); + (*data).insert(P); + i++; + } + std::pair 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 > *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 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 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 +extern "C" { +#include "../jsmn.h" +} +#include +#include +#include +#include + +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 *P); +int get_array_of_primitives(const char *js, const jsmntok_t *t, int i, + std::vector *V); +int get_struct(const char *js, const jsmntok_t *t, int i, + std::map *data); +int get_struct_of_array( + const char *js, const jsmntok_t *t, int i, + std::unordered_map > *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