Message ID | 166793221692.3768752.18351228388707416243.stgit@djiang5-desk3.ch.intel.com |
---|---|
State | New, archived |
Headers | show |
Series | cxl: add monitor support for trace events | expand |
On Tue, 08 Nov 2022 11:30:16 -0700 Dave Jiang <dave.jiang@intel.com> wrote: > Add function that creates an event trace instance and utilize the cxl event > trace common functions to extract interested events from the trace buffer. > The monitoring function will pend on an epoll fd and wait for new events > to appear in the trace buffer. > > Signed-off-by: Dave Jiang <dave.jiang@intel.com> > --- > cxl/meson.build | 1 > cxl/monitor.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 141 insertions(+) > create mode 100644 cxl/monitor.c > > diff --git a/cxl/meson.build b/cxl/meson.build > index c59876262e76..eb8b2b1070ed 100644 > --- a/cxl/meson.build > +++ b/cxl/meson.build > @@ -8,6 +8,7 @@ cxl_src = [ > 'json.c', > 'filter.c', > 'event_trace.c', > + 'monitor.c', > ] > > cxl_tool = executable('cxl', > diff --git a/cxl/monitor.c b/cxl/monitor.c > new file mode 100644 > index 000000000000..c3f7e3639ec0 > --- /dev/null > +++ b/cxl/monitor.c > @@ -0,0 +1,140 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// Copyright (C) 2022, Intel Corp. All rights reserved. > +/* Some bits copied from ndctl monitor code */ > +#include <stdio.h> > +#include <unistd.h> > +#include <errno.h> > +#include <json-c/json.h> > +#include <libgen.h> > +#include <time.h> > +#include <dirent.h> > +#include <ccan/list/list.h> > +#include <util/json.h> > +#include <util/util.h> > +#include <util/parse-options.h> > +#include <util/parse-configs.h> > +#include <util/strbuf.h> > +#include <sys/epoll.h> > +#include <sys/stat.h> > +#include <traceevent/event-parse.h> > +#include <tracefs/tracefs.h> > +#include <cxl/libcxl.h> > + > +/* reuse the core log helpers for the monitor logger */ > +#ifndef ENABLE_LOGGING > +#define ENABLE_LOGGING > +#endif > +#ifndef ENABLE_DEBUG > +#define ENABLE_DEBUG > +#endif > +#include <util/log.h> > + > +#include "event_trace.h" > + > +static const char *cxl_system = "cxl"; > + > +static struct monitor { > + struct log_ctx ctx; > + FILE *log_file; > + bool human; > +} monitor; > + > +static int monitor_event(struct cxl_ctx *ctx) > +{ > + int fd, epollfd, rc = 0, timeout = -1; > + struct epoll_event ev, *events; > + struct tracefs_instance *inst; > + struct event_ctx ectx; > + int jflag; > + > + events = calloc(1, sizeof(struct epoll_event)); > + if (!events) { > + err(&monitor, "alloc for events error\n"); > + return -ENOMEM; > + } > + > + epollfd = epoll_create1(0); > + if (epollfd == -1) { > + rc = -errno; > + err(&monitor, "epoll_create1() error: %d\n", rc); > + goto epoll_err; > + } > + > + inst = tracefs_instance_create("cxl_monitor"); > + if (!inst) { > + rc = -errno; > + err(&monitor, "tracefs_instance_create( failed: %d\n", rc); > + goto inst_err; > + } > + > + fd = tracefs_instance_file_open(inst, "trace_pipe", -1); FYI, libtracefs now has an API to read the raw trace file directly. https://www.trace-cmd.org/Documentation/libtracefs-doc/libtracefs-cpu.html as well iterate over the live stream: https://www.trace-cmd.org/Documentation/libtracefs-doc/libtracefs-iterator.html -- Steve > + if (fd < 0) { > + rc = fd; > + err(&monitor, "tracefs_instance_file_open() err: %d\n", rc); > + goto inst_file_err; > + } > + > + memset(&ev, 0, sizeof(ev)); > + ev.events = EPOLLIN; > + ev.data.fd = fd; > + > + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) != 0) { > + rc = -errno; > + err(&monitor, "epoll_ctl() error: %d\n", rc); > + goto epoll_ctl_err; > + } > + > + rc = cxl_event_tracing_enable(inst, cxl_system, NULL); > + if (rc < 0) { > + err(&monitor, "cxl_trace_event_enable() failed: %d\n", rc); > + goto event_en_err; > + } > + > + memset(&ectx, 0, sizeof(ectx)); > + ectx.system = cxl_system; > + if (monitor.human) > + jflag = JSON_C_TO_STRING_PRETTY; > + else > + jflag = JSON_C_TO_STRING_PLAIN; > + > + while (1) { > + struct jlist_node *jnode, *next; > + > + rc = epoll_wait(epollfd, events, 1, timeout); > + if (rc < 0) { > + rc = -errno; > + if (errno != EINTR) > + err(&monitor, "epoll_wait error: %d\n", -errno); > + break; > + } > + > + list_head_init(&ectx.jlist_head); > + rc = cxl_parse_events(inst, &ectx); > + if (rc < 0) > + goto parse_err; > + > + if (list_empty(&ectx.jlist_head)) > + continue; > + > + list_for_each_safe(&ectx.jlist_head, jnode, next, list) { > + notice(&monitor, "%s\n", > + json_object_to_json_string_ext(jnode->jobj, jflag)); > + list_del(&jnode->list); > + json_object_put(jnode->jobj); > + free(jnode); > + } > + } > + > +parse_err: > + rc = cxl_event_tracing_disable(inst); > +event_en_err: > +epoll_ctl_err: > + close(fd); > +inst_file_err: > + tracefs_instance_free(inst); > +inst_err: > + close(epollfd); > +epoll_err: > + free(events); > + return rc; > +} >
On 11/17/2022 11:37 AM, Steven Rostedt wrote: > On Tue, 08 Nov 2022 11:30:16 -0700 > Dave Jiang <dave.jiang@intel.com> wrote: > >> Add function that creates an event trace instance and utilize the cxl event >> trace common functions to extract interested events from the trace buffer. >> The monitoring function will pend on an epoll fd and wait for new events >> to appear in the trace buffer. >> >> Signed-off-by: Dave Jiang <dave.jiang@intel.com> >> --- >> cxl/meson.build | 1 >> cxl/monitor.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 141 insertions(+) >> create mode 100644 cxl/monitor.c >> >> diff --git a/cxl/meson.build b/cxl/meson.build >> index c59876262e76..eb8b2b1070ed 100644 >> --- a/cxl/meson.build >> +++ b/cxl/meson.build >> @@ -8,6 +8,7 @@ cxl_src = [ >> 'json.c', >> 'filter.c', >> 'event_trace.c', >> + 'monitor.c', >> ] >> >> cxl_tool = executable('cxl', >> diff --git a/cxl/monitor.c b/cxl/monitor.c >> new file mode 100644 >> index 000000000000..c3f7e3639ec0 >> --- /dev/null >> +++ b/cxl/monitor.c >> @@ -0,0 +1,140 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +// Copyright (C) 2022, Intel Corp. All rights reserved. >> +/* Some bits copied from ndctl monitor code */ >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <errno.h> >> +#include <json-c/json.h> >> +#include <libgen.h> >> +#include <time.h> >> +#include <dirent.h> >> +#include <ccan/list/list.h> >> +#include <util/json.h> >> +#include <util/util.h> >> +#include <util/parse-options.h> >> +#include <util/parse-configs.h> >> +#include <util/strbuf.h> >> +#include <sys/epoll.h> >> +#include <sys/stat.h> >> +#include <traceevent/event-parse.h> >> +#include <tracefs/tracefs.h> >> +#include <cxl/libcxl.h> >> + >> +/* reuse the core log helpers for the monitor logger */ >> +#ifndef ENABLE_LOGGING >> +#define ENABLE_LOGGING >> +#endif >> +#ifndef ENABLE_DEBUG >> +#define ENABLE_DEBUG >> +#endif >> +#include <util/log.h> >> + >> +#include "event_trace.h" >> + >> +static const char *cxl_system = "cxl"; >> + >> +static struct monitor { >> + struct log_ctx ctx; >> + FILE *log_file; >> + bool human; >> +} monitor; >> + >> +static int monitor_event(struct cxl_ctx *ctx) >> +{ >> + int fd, epollfd, rc = 0, timeout = -1; >> + struct epoll_event ev, *events; >> + struct tracefs_instance *inst; >> + struct event_ctx ectx; >> + int jflag; >> + >> + events = calloc(1, sizeof(struct epoll_event)); >> + if (!events) { >> + err(&monitor, "alloc for events error\n"); >> + return -ENOMEM; >> + } >> + >> + epollfd = epoll_create1(0); >> + if (epollfd == -1) { >> + rc = -errno; >> + err(&monitor, "epoll_create1() error: %d\n", rc); >> + goto epoll_err; >> + } >> + >> + inst = tracefs_instance_create("cxl_monitor"); >> + if (!inst) { >> + rc = -errno; >> + err(&monitor, "tracefs_instance_create( failed: %d\n", rc); >> + goto inst_err; >> + } >> + >> + fd = tracefs_instance_file_open(inst, "trace_pipe", -1); > > FYI, libtracefs now has an API to read the raw trace file directly. > > https://www.trace-cmd.org/Documentation/libtracefs-doc/libtracefs-cpu.html > > as well iterate over the live stream: > > https://www.trace-cmd.org/Documentation/libtracefs-doc/libtracefs-iterator.html Hi Steve, After looking those over, I'm uncertain how the new APIs would apply here. I'm only using fd to the trace_pipe for epoll notification of new events for the instance. Otherwise I'm using tracefs_iterate_raw_events() to retrieve and parse the events. > > -- Steve > >> + if (fd < 0) { >> + rc = fd; >> + err(&monitor, "tracefs_instance_file_open() err: %d\n", rc); >> + goto inst_file_err; >> + } >> + >> + memset(&ev, 0, sizeof(ev)); >> + ev.events = EPOLLIN; >> + ev.data.fd = fd; >> + >> + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) != 0) { >> + rc = -errno; >> + err(&monitor, "epoll_ctl() error: %d\n", rc); >> + goto epoll_ctl_err; >> + } >> + >> + rc = cxl_event_tracing_enable(inst, cxl_system, NULL); >> + if (rc < 0) { >> + err(&monitor, "cxl_trace_event_enable() failed: %d\n", rc); >> + goto event_en_err; >> + } >> + >> + memset(&ectx, 0, sizeof(ectx)); >> + ectx.system = cxl_system; >> + if (monitor.human) >> + jflag = JSON_C_TO_STRING_PRETTY; >> + else >> + jflag = JSON_C_TO_STRING_PLAIN; >> + >> + while (1) { >> + struct jlist_node *jnode, *next; >> + >> + rc = epoll_wait(epollfd, events, 1, timeout); >> + if (rc < 0) { >> + rc = -errno; >> + if (errno != EINTR) >> + err(&monitor, "epoll_wait error: %d\n", -errno); >> + break; >> + } >> + >> + list_head_init(&ectx.jlist_head); >> + rc = cxl_parse_events(inst, &ectx); >> + if (rc < 0) >> + goto parse_err; >> + >> + if (list_empty(&ectx.jlist_head)) >> + continue; >> + >> + list_for_each_safe(&ectx.jlist_head, jnode, next, list) { >> + notice(&monitor, "%s\n", >> + json_object_to_json_string_ext(jnode->jobj, jflag)); >> + list_del(&jnode->list); >> + json_object_put(jnode->jobj); >> + free(jnode); >> + } >> + } >> + >> +parse_err: >> + rc = cxl_event_tracing_disable(inst); >> +event_en_err: >> +epoll_ctl_err: >> + close(fd); >> +inst_file_err: >> + tracefs_instance_free(inst); >> +inst_err: >> + close(epollfd); >> +epoll_err: >> + free(events); >> + return rc; >> +} >> >
On Thu, 17 Nov 2022 13:29:42 -0700 Dave Jiang <dave.jiang@intel.com> wrote: > > as well iterate over the live stream: > > > > https://www.trace-cmd.org/Documentation/libtracefs-doc/libtracefs-iterator.html > > Hi Steve, > After looking those over, I'm uncertain how the new APIs would apply > here. I'm only using fd to the trace_pipe for epoll notification of new > events for the instance. Otherwise I'm using > tracefs_iterate_raw_events() to retrieve and parse the events. Ah sorry, I didn't look farther to see how it was being used. And I plan on adding a tracefs_wait(instance, percentage) function that will do just that, but haven't implemented it yet. -- Steve
On 11/17/2022 1:33 PM, Steven Rostedt wrote: > On Thu, 17 Nov 2022 13:29:42 -0700 > Dave Jiang <dave.jiang@intel.com> wrote: > >>> as well iterate over the live stream: >>> >>> https://www.trace-cmd.org/Documentation/libtracefs-doc/libtracefs-iterator.html >> >> Hi Steve, >> After looking those over, I'm uncertain how the new APIs would apply >> here. I'm only using fd to the trace_pipe for epoll notification of new >> events for the instance. Otherwise I'm using >> tracefs_iterate_raw_events() to retrieve and parse the events. > > Ah sorry, I didn't look farther to see how it was being used. > > And I plan on adding a tracefs_wait(instance, percentage) function that > will do just that, but haven't implemented it yet. Ah great! Looking forward to convert the code to use that in the future. > > -- Steve
diff --git a/cxl/meson.build b/cxl/meson.build index c59876262e76..eb8b2b1070ed 100644 --- a/cxl/meson.build +++ b/cxl/meson.build @@ -8,6 +8,7 @@ cxl_src = [ 'json.c', 'filter.c', 'event_trace.c', + 'monitor.c', ] cxl_tool = executable('cxl', diff --git a/cxl/monitor.c b/cxl/monitor.c new file mode 100644 index 000000000000..c3f7e3639ec0 --- /dev/null +++ b/cxl/monitor.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2022, Intel Corp. All rights reserved. +/* Some bits copied from ndctl monitor code */ +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <json-c/json.h> +#include <libgen.h> +#include <time.h> +#include <dirent.h> +#include <ccan/list/list.h> +#include <util/json.h> +#include <util/util.h> +#include <util/parse-options.h> +#include <util/parse-configs.h> +#include <util/strbuf.h> +#include <sys/epoll.h> +#include <sys/stat.h> +#include <traceevent/event-parse.h> +#include <tracefs/tracefs.h> +#include <cxl/libcxl.h> + +/* reuse the core log helpers for the monitor logger */ +#ifndef ENABLE_LOGGING +#define ENABLE_LOGGING +#endif +#ifndef ENABLE_DEBUG +#define ENABLE_DEBUG +#endif +#include <util/log.h> + +#include "event_trace.h" + +static const char *cxl_system = "cxl"; + +static struct monitor { + struct log_ctx ctx; + FILE *log_file; + bool human; +} monitor; + +static int monitor_event(struct cxl_ctx *ctx) +{ + int fd, epollfd, rc = 0, timeout = -1; + struct epoll_event ev, *events; + struct tracefs_instance *inst; + struct event_ctx ectx; + int jflag; + + events = calloc(1, sizeof(struct epoll_event)); + if (!events) { + err(&monitor, "alloc for events error\n"); + return -ENOMEM; + } + + epollfd = epoll_create1(0); + if (epollfd == -1) { + rc = -errno; + err(&monitor, "epoll_create1() error: %d\n", rc); + goto epoll_err; + } + + inst = tracefs_instance_create("cxl_monitor"); + if (!inst) { + rc = -errno; + err(&monitor, "tracefs_instance_create( failed: %d\n", rc); + goto inst_err; + } + + fd = tracefs_instance_file_open(inst, "trace_pipe", -1); + if (fd < 0) { + rc = fd; + err(&monitor, "tracefs_instance_file_open() err: %d\n", rc); + goto inst_file_err; + } + + memset(&ev, 0, sizeof(ev)); + ev.events = EPOLLIN; + ev.data.fd = fd; + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) != 0) { + rc = -errno; + err(&monitor, "epoll_ctl() error: %d\n", rc); + goto epoll_ctl_err; + } + + rc = cxl_event_tracing_enable(inst, cxl_system, NULL); + if (rc < 0) { + err(&monitor, "cxl_trace_event_enable() failed: %d\n", rc); + goto event_en_err; + } + + memset(&ectx, 0, sizeof(ectx)); + ectx.system = cxl_system; + if (monitor.human) + jflag = JSON_C_TO_STRING_PRETTY; + else + jflag = JSON_C_TO_STRING_PLAIN; + + while (1) { + struct jlist_node *jnode, *next; + + rc = epoll_wait(epollfd, events, 1, timeout); + if (rc < 0) { + rc = -errno; + if (errno != EINTR) + err(&monitor, "epoll_wait error: %d\n", -errno); + break; + } + + list_head_init(&ectx.jlist_head); + rc = cxl_parse_events(inst, &ectx); + if (rc < 0) + goto parse_err; + + if (list_empty(&ectx.jlist_head)) + continue; + + list_for_each_safe(&ectx.jlist_head, jnode, next, list) { + notice(&monitor, "%s\n", + json_object_to_json_string_ext(jnode->jobj, jflag)); + list_del(&jnode->list); + json_object_put(jnode->jobj); + free(jnode); + } + } + +parse_err: + rc = cxl_event_tracing_disable(inst); +event_en_err: +epoll_ctl_err: + close(fd); +inst_file_err: + tracefs_instance_free(inst); +inst_err: + close(epollfd); +epoll_err: + free(events); + return rc; +}
Add function that creates an event trace instance and utilize the cxl event trace common functions to extract interested events from the trace buffer. The monitoring function will pend on an epoll fd and wait for new events to appear in the trace buffer. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- cxl/meson.build | 1 cxl/monitor.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 cxl/monitor.c