Message ID | 166318847529.3087953.18405653106756321818.stgit@djiang5-desk3.ch.intel.com |
---|---|
State | Superseded |
Delegated to: | Vishal Verma |
Headers | show |
Series | ndctl: cxl: add monitor support for trace events | expand |
On Wed, Sep 14, 2022 at 01:47:55PM -0700, Dave Jiang wrote: > Add the helper function that parses a trace event captured by > libtraceevent in a tep handle. All the parsed fields are added to a json > object. The json object is added to the provided list in the input parameter. > > Signed-off-by: Dave Jiang <dave.jiang@intel.com> Hi Dave, I've been using these parsing patches, and it all works for the purpose of parsing the cxl device poison list. Tested-by: Alison Schofield <alison.schofield@intel.com> One comment below... -snip- > --- > + > + for (i = 0; fields[i]; i++) { > + struct tep_format_field *f = fields[i]; > + int len; > + char *tmp; > + > + tmp = strcasestr(f->type, "char[]"); > + if (tmp) { /* event field is a string */ > + char *str; > + > + str = tep_get_field_raw(NULL, event, f->name, record, &len, 0); > + if (!str) > + continue; > + > + jobj = json_object_new_string(str); > + if (!jobj) { > + rc = -ENOMEM; > + goto err; > + } > + > + json_object_object_add(jevent, f->name, jobj); > + } else if (f->arraylen) { /* data array */ > + unsigned char *data; > + int chunks; > + > + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); > + if (!data) > + continue; > + > + /* check to see if we have a UUID */ > + tmp = strcasestr(f->name, "uuid"); > + if (tmp && f->arraylen == 16) { > + char uuid[SYSFS_ATTR_SIZE]; > + > + uuid_unparse(data, uuid); > + jobj = json_object_new_string(uuid); > + if (!jobj) { > + rc = -ENOMEM; > + goto err; > + } > + > + json_object_object_add(jevent, f->name, jobj); > + continue; > + } Insted of comparing the field name, is it possible to check for f->type of 'uuid_t'? > + > + jarray = json_object_new_array(); > + if (!jarray) { > + rc = -ENOMEM; > + goto err; > + } > + > + chunks = f->size / f->elementsize; > + for (j = 0; j < chunks; j++) { > + jobj = num_to_json(data, f->elementsize); > + if (!jobj) { > + json_object_put(jarray); > + return -ENOMEM; > + } > + json_object_array_add(jarray, jobj); > + data += f->elementsize; > + } > + > + json_object_object_add(jevent, f->name, jarray); > + } else { /* single number */ > + char *data; > + > + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); > + if (!data) > + continue; > + > + jobj = num_to_json(data, f->elementsize); > + if (!jobj) { > + rc = -ENOMEM; > + goto err; > + } > + > + json_object_object_add(jevent, f->name, jobj); > + } > + } > + > + list_add_tail(jlist_head, &jnode->list); > + return 0; > + > +err: > + json_object_put(jevent); > +err_jevent: > + free(jnode); > + return rc; > +} snip
On 10/31/2022 1:01 PM, Alison Schofield wrote: > On Wed, Sep 14, 2022 at 01:47:55PM -0700, Dave Jiang wrote: >> Add the helper function that parses a trace event captured by >> libtraceevent in a tep handle. All the parsed fields are added to a json >> object. The json object is added to the provided list in the input parameter. >> >> Signed-off-by: Dave Jiang <dave.jiang@intel.com> > > Hi Dave, > > I've been using these parsing patches, and it all works for the purpose > of parsing the cxl device poison list. > > Tested-by: Alison Schofield <alison.schofield@intel.com> Thanks! > > One comment below... > > -snip- > >> --- >> + >> + for (i = 0; fields[i]; i++) { >> + struct tep_format_field *f = fields[i]; >> + int len; >> + char *tmp; >> + >> + tmp = strcasestr(f->type, "char[]"); >> + if (tmp) { /* event field is a string */ >> + char *str; >> + >> + str = tep_get_field_raw(NULL, event, f->name, record, &len, 0); >> + if (!str) >> + continue; >> + >> + jobj = json_object_new_string(str); >> + if (!jobj) { >> + rc = -ENOMEM; >> + goto err; >> + } >> + >> + json_object_object_add(jevent, f->name, jobj); >> + } else if (f->arraylen) { /* data array */ >> + unsigned char *data; >> + int chunks; >> + >> + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); >> + if (!data) >> + continue; >> + >> + /* check to see if we have a UUID */ >> + tmp = strcasestr(f->name, "uuid"); >> + if (tmp && f->arraylen == 16) { >> + char uuid[SYSFS_ATTR_SIZE]; >> + >> + uuid_unparse(data, uuid); >> + jobj = json_object_new_string(uuid); >> + if (!jobj) { >> + rc = -ENOMEM; >> + goto err; >> + } >> + >> + json_object_object_add(jevent, f->name, jobj); >> + continue; >> + } > > Insted of comparing the field name, is it possible to check for > f->type of 'uuid_t'? > Yes. I talked to Ira and he'll change his uuid to uuid_t from u8[]. That should make it better. Thanks for pointing that out. > >> + >> + jarray = json_object_new_array(); >> + if (!jarray) { >> + rc = -ENOMEM; >> + goto err; >> + } >> + >> + chunks = f->size / f->elementsize; >> + for (j = 0; j < chunks; j++) { >> + jobj = num_to_json(data, f->elementsize); >> + if (!jobj) { >> + json_object_put(jarray); >> + return -ENOMEM; >> + } >> + json_object_array_add(jarray, jobj); >> + data += f->elementsize; >> + } >> + >> + json_object_object_add(jevent, f->name, jarray); >> + } else { /* single number */ >> + char *data; >> + >> + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); >> + if (!data) >> + continue; >> + >> + jobj = num_to_json(data, f->elementsize); >> + if (!jobj) { >> + rc = -ENOMEM; >> + goto err; >> + } >> + >> + json_object_object_add(jevent, f->name, jobj); >> + } >> + } >> + >> + list_add_tail(jlist_head, &jnode->list); >> + return 0; >> + >> +err: >> + json_object_put(jevent); >> +err_jevent: >> + free(jnode); >> + return rc; >> +} > > snip >
On Mon, Oct 31, 2022 at 02:37:02PM -0700, Jiang, Dave wrote: > > > On 10/31/2022 1:01 PM, Alison Schofield wrote: [snip] > > > + /* check to see if we have a UUID */ > > > + tmp = strcasestr(f->name, "uuid"); > > > + if (tmp && f->arraylen == 16) { > > > + char uuid[SYSFS_ATTR_SIZE]; > > > + > > > + uuid_unparse(data, uuid); > > > + jobj = json_object_new_string(uuid); > > > + if (!jobj) { > > > + rc = -ENOMEM; > > > + goto err; > > > + } > > > + > > > + json_object_object_add(jevent, f->name, jobj); > > > + continue; > > > + } > > > > Insted of comparing the field name, is it possible to check for > > f->type of 'uuid_t'? > > > > Yes. I talked to Ira and he'll change his uuid to uuid_t from u8[]. That > should make it better. Thanks for pointing that out. So after unborking my qemu I was able to actually try this. And it did not work the way I thought it would. However, in the end Dave and I figured out how to make it work using the __field_struct() TP entry type in the kernel and some mods to cxl. Thanks Alison this is much better. Ira
diff --git a/cxl/event_trace.c b/cxl/event_trace.c new file mode 100644 index 000000000000..ffa2a9b9b036 --- /dev/null +++ b/cxl/event_trace.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2022, Intel Corp. All rights reserved. +#include <stdio.h> +#include <json-c/json.h> +#include <util/json.h> +#include <util/util.h> +#include <util/parse-options.h> +#include <util/parse-configs.h> +#include <util/strbuf.h> +#include <util/sysfs.h> +#include <ccan/list/list.h> +#include <ndctl/ndctl.h> +#include <ndctl/libndctl.h> +#include <sys/epoll.h> +#include <sys/stat.h> +#include <libcxl.h> +#include <uuid/uuid.h> +#include <traceevent/event-parse.h> +#include "json.h" +#include "event_trace.h" + +#define _GNU_SOURCE +#include <string.h> + +static struct json_object *num_to_json(void *num, int size) +{ + if (size <= 4) + return json_object_new_int(*(int *)num); + + return util_json_object_hex(*(unsigned long long *)num, 0); +} + +static int cxl_event_to_json_callback(struct tep_event *event, + struct tep_record *record, struct list_head *jlist_head) +{ + struct tep_format_field **fields; + struct json_object *jevent, *jobj, *jarray; + struct jlist_node *jnode; + int i, j, rc = 0; + + jnode = malloc(sizeof(*jnode)); + if (!jnode) + return -ENOMEM; + + jevent = json_object_new_object(); + if (!jevent) { + rc = -ENOMEM; + goto err_jevent; + } + jnode->jobj = jevent; + + fields = tep_event_fields(event); + if (!fields) { + rc = -ENOENT; + goto err; + } + + jobj = json_object_new_string(event->system); + if (!jobj) { + rc = -ENOMEM; + goto err; + } + json_object_object_add(jevent, "system", jobj); + + jobj = json_object_new_string(event->name); + if (!jobj) { + rc = -ENOMEM; + goto err; + } + json_object_object_add(jevent, "event", jobj); + + jobj = json_object_new_uint64(record->ts); + if (!jobj) { + rc = -ENOMEM; + goto err; + } + json_object_object_add(jevent, "timestamp", jobj); + + for (i = 0; fields[i]; i++) { + struct tep_format_field *f = fields[i]; + int len; + char *tmp; + + tmp = strcasestr(f->type, "char[]"); + if (tmp) { /* event field is a string */ + char *str; + + str = tep_get_field_raw(NULL, event, f->name, record, &len, 0); + if (!str) + continue; + + jobj = json_object_new_string(str); + if (!jobj) { + rc = -ENOMEM; + goto err; + } + + json_object_object_add(jevent, f->name, jobj); + } else if (f->arraylen) { /* data array */ + unsigned char *data; + int chunks; + + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); + if (!data) + continue; + + /* check to see if we have a UUID */ + tmp = strcasestr(f->name, "uuid"); + if (tmp && f->arraylen == 16) { + char uuid[SYSFS_ATTR_SIZE]; + + uuid_unparse(data, uuid); + jobj = json_object_new_string(uuid); + if (!jobj) { + rc = -ENOMEM; + goto err; + } + + json_object_object_add(jevent, f->name, jobj); + continue; + } + + jarray = json_object_new_array(); + if (!jarray) { + rc = -ENOMEM; + goto err; + } + + chunks = f->size / f->elementsize; + for (j = 0; j < chunks; j++) { + jobj = num_to_json(data, f->elementsize); + if (!jobj) { + json_object_put(jarray); + return -ENOMEM; + } + json_object_array_add(jarray, jobj); + data += f->elementsize; + } + + json_object_object_add(jevent, f->name, jarray); + } else { /* single number */ + char *data; + + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); + if (!data) + continue; + + jobj = num_to_json(data, f->elementsize); + if (!jobj) { + rc = -ENOMEM; + goto err; + } + + json_object_object_add(jevent, f->name, jobj); + } + } + + list_add_tail(jlist_head, &jnode->list); + return 0; + +err: + json_object_put(jevent); +err_jevent: + free(jnode); + return rc; +} diff --git a/cxl/event_trace.h b/cxl/event_trace.h new file mode 100644 index 000000000000..00975a0b5680 --- /dev/null +++ b/cxl/event_trace.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2022 Intel Corporation. All rights reserved. */ +#ifndef __CXL_EVENT_TRACE_H__ +#define __CXL_EVENT_TRACE_H__ + +#include <json-c/json.h> +#include <ccan/list/list.h> + +struct jlist_node { + struct json_object *jobj; + struct list_node list; +}; + +#endif diff --git a/cxl/meson.build b/cxl/meson.build index f2474aaa6e2e..8c7733431613 100644 --- a/cxl/meson.build +++ b/cxl/meson.build @@ -7,6 +7,7 @@ cxl_src = [ 'memdev.c', 'json.c', 'filter.c', + 'event_trace.c', ] cxl_tool = executable('cxl', @@ -19,6 +20,7 @@ cxl_tool = executable('cxl', kmod, json, versiondep, + traceevent, ], install : true, install_dir : rootbindir, diff --git a/meson.build b/meson.build index 20a646d135c7..f611e0bdd7f3 100644 --- a/meson.build +++ b/meson.build @@ -142,6 +142,7 @@ kmod = dependency('libkmod') libudev = dependency('libudev') uuid = dependency('uuid') json = dependency('json-c') +traceevent = dependency('libtraceevent') if get_option('docs').enabled() if get_option('asciidoctor').enabled() asciidoc = find_program('asciidoctor', required : true)
Add the helper function that parses a trace event captured by libtraceevent in a tep handle. All the parsed fields are added to a json object. The json object is added to the provided list in the input parameter. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- cxl/event_trace.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cxl/event_trace.h | 14 ++++ cxl/meson.build | 2 + meson.build | 1 4 files changed, 183 insertions(+) create mode 100644 cxl/event_trace.c create mode 100644 cxl/event_trace.h