Skip to content

Commit

Permalink
cxl: add a helper to parse trace events into a json object
Browse files Browse the repository at this point in the history
Add a 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.

Tested-by: Alison Schofield <alison.schofield@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/166803885399.145141.7371810852032502111.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
  • Loading branch information
davejiang authored and stellarhopper committed Feb 3, 2023
1 parent 0872062 commit 8dedc6c
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 0 deletions.
193 changes: 193 additions & 0 deletions cxl/event_trace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2022, Intel Corp. All rights reserved.
#include <stdio.h>
#include <errno.h>
#include <json-c/json.h>
#include <util/json.h>
#include <util/util.h>
#include <util/strbuf.h>
#include <ccan/list/list.h>
#include <uuid/uuid.h>
#include <traceevent/event-parse.h>
#include "event_trace.h"

#define _GNU_SOURCE
#include <string.h>

static struct json_object *num_to_json(void *num, int elem_size, unsigned long flags)
{
bool sign = flags & TEP_FIELD_IS_SIGNED;
int64_t val = 0;

/* special case 64 bit as the call depends on sign */
if (elem_size == 8) {
if (sign)
return json_object_new_int64(*(int64_t *)num);
else
return json_object_new_uint64(*(uint64_t *)num);
}

/* All others fit in a signed 64 bit */
switch (elem_size) {
case 1:
if (sign)
val = *(int8_t *)num;
else
val = *(uint8_t *)num;
break;
case 2:
if (sign)
val = *(int16_t *)num;
else
val = *(uint16_t *)num;
break;
case 4:
if (sign)
val = *(int32_t *)num;
else
val = *(uint32_t *)num;
break;
default:
/*
* Odd sizes are converted in the kernel to one of the above.
* It is an error to see them here.
*/
return NULL;
}

return json_object_new_int64(val);
}

static int cxl_event_to_json(struct tep_event *event, struct tep_record *record,
struct list_head *jlist_head)
{
struct json_object *jevent, *jobj, *jarray;
struct tep_format_field **fields;
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_jnode;
}
jnode->jobj = jevent;

fields = tep_event_fields(event);
if (!fields) {
rc = -ENOENT;
goto err_jevent;
}

jobj = json_object_new_string(event->system);
if (!jobj) {
rc = -ENOMEM;
goto err_jevent;
}
json_object_object_add(jevent, "system", jobj);

jobj = json_object_new_string(event->name);
if (!jobj) {
rc = -ENOMEM;
goto err_jevent;
}
json_object_object_add(jevent, "event", jobj);

jobj = json_object_new_uint64(record->ts);
if (!jobj) {
rc = -ENOMEM;
goto err_jevent;
}
json_object_object_add(jevent, "timestamp", jobj);

for (i = 0; fields[i]; i++) {
struct tep_format_field *f = fields[i];
int len;

if (f->flags & TEP_FIELD_IS_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_jevent;
}

json_object_object_add(jevent, f->name, jobj);
} else if (f->flags & TEP_FIELD_IS_ARRAY) {
unsigned char *data;
int chunks;

data = tep_get_field_raw(NULL, event, f->name, record, &len, 0);
if (!data)
continue;

jarray = json_object_new_array();
if (!jarray) {
rc = -ENOMEM;
goto err_jevent;
}

chunks = f->size / f->elementsize;
for (j = 0; j < chunks; j++) {
jobj = num_to_json(data, f->elementsize, f->flags);
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 */
unsigned char *data;
char *tmp;

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->type, "uuid_t");
if (tmp) {
char uuid[40];

uuid_unparse(data, uuid);
jobj = json_object_new_string(uuid);
if (!jobj) {
rc = -ENOMEM;
goto err_jevent;
}

json_object_object_add(jevent, f->name, jobj);
continue;
}

jobj = num_to_json(data, f->elementsize, f->flags);
if (!jobj) {
rc = -ENOMEM;
goto err_jevent;
}

json_object_object_add(jevent, f->name, jobj);
}
}

list_add_tail(jlist_head, &jnode->list);
return 0;

err_jevent:
json_object_put(jevent);
err_jnode:
free(jnode);
return rc;
}
14 changes: 14 additions & 0 deletions cxl/event_trace.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions cxl/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ cxl_src = [
'memdev.c',
'json.c',
'filter.c',
'event_trace.c',
]

cxl_tool = executable('cxl',
Expand All @@ -19,6 +20,7 @@ cxl_tool = executable('cxl',
kmod,
json,
versiondep,
traceevent,
],
install : true,
install_dir : rootbindir,
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,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)
Expand Down

0 comments on commit 8dedc6c

Please sign in to comment.