From: Steven Rostedt <rostedt@goodmis.org>
To: "Yordan Karadzhov (VMware)" <y.karadz@gmail.com>
Cc: linux-trace-devel@vger.kernel.org
Subject: Re: [PATCH 7/7] kernel-shark-qt: Add a plugin for sched events.
Date: Thu, 30 Aug 2018 13:38:32 -0400 [thread overview]
Message-ID: <20180830133832.657a8eab@gandalf.local.home> (raw)
In-Reply-To: <20180829164224.20677-8-y.karadz@gmail.com>
On Wed, 29 Aug 2018 19:42:24 +0300
"Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:
> --- /dev/null
> +++ b/kernel-shark-qt/src/plugins/SchedEvents.cpp
> @@ -0,0 +1,258 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +
> +/*
> + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +/**
> + * @file SchedEvents.cpp
> + * @brief Plugin for Sched events.
> + */
> +
> +// KernelShark
> +#include "libkshark.h"
> +#include "plugins/sched_events.h"
> +#include "KsPlotTools.hpp"
> +#include "KsPlugins.hpp"
> +
> +extern struct plugin_sched_context *plugin_sched_context_handler;
> +
> +static int plugin_get_wakeup_pid_lazy(struct kshark_context *kshark_ctx,
> + const struct kshark_entry *e)
> +{
> + struct plugin_sched_context *plugin_ctx;
> + struct tep_record *record;
> + unsigned long long val;
> +
> + plugin_ctx = plugin_sched_context_handler;
> + record = kshark_read_at(kshark_ctx, e->offset);
> +
> + tep_read_number_field(plugin_ctx->sched_wakeup_pid_field,
> + record->data, &val);
> + free(record);
> +
> + return val;
> +}
> +
> +static void openBox(KsPlot::Rectangle **rec,
> + const KsPlot::Bin &bin,
> + int height)
> +{
> + if (!*rec)
> + *rec = new KsPlot::Rectangle;
BTW, for exception handling here (if new fails), should there be some
sort of comments somewhere, about what types of exceptions should be
caught. This is more a general question and not specific to this code
here.
With C, one needs to always check for the return. Now, with C++ we can
do try { } catch, but then we need to be able to clean everything up.
I honestly think that try/catch can end up being sloppier than the C
way, but C is a bit more work to get right.
> +
> + (**rec).setFill(false);
> + (**rec).setPoint(0, bin._base.x() - 1,
> + bin._base.y() - height);
> +
> + (**rec).setPoint(1, bin._base.x() - 1,
> + bin._base.y() - 1);
> +}
> +
> +static void closeBox(KsPlot::Rectangle **rec,
> + const KsPlot::Bin &bin,
> + int height,
> + KsPlot::PlotObjList *list)
> +{
> + if (*rec == nullptr)
> + return;
> +
> + if (bin._base.x() - (**rec).getPoint(0)->x < 4) {
Let's keep from using hard coded numbers. Why 4? We should make this at
least a macro that can be changed. Or perhaps a variable in some class?
> + /* This box is too small.
> + * Don't try to plot it. */
> + delete *rec;
> + *rec = nullptr;
> + return;
> + }
> +
> + (**rec).setPoint(3, bin._base.x() - 1,
> + bin._base.y() - height);
> +
> + (**rec).setPoint(2, bin._base.x() - 1,
> + bin._base.y() - 1);
> +
> + list->push_front(*rec);
> + *rec = nullptr;
> +}
> +
> +static void schedWakeupPluginDraw(struct plugin_sched_context *plugin_ctx,
> + kshark_trace_histo *histo,
> + KsPlot::Graph *graph,
> + int pid,
> + KsPlot::PlotObjList *shapes)
> +{
> + const kshark_entry *entryF, *entryB;
> + KsPlot::Rectangle *rec = nullptr;
> + kshark_context *kshark_ctx(NULL);
> + kshark_entry_collection *col;
> + kshark_instance(&kshark_ctx);
> + int wakeup_pid;
> +
> + col = kshark_find_data_collection(kshark_ctx->collections,
> + kshark_match_pid, pid);
If col is NULL, should we just return right away? Or is col OK to be
NULL?
> +
> + size_t nBins = graph->size();
> + for (size_t bin = 0; bin < nBins; ++bin) {
> + if (ksmodel_bin_count(histo, bin) > 500)
Why 500?
> + continue;
> +
> + /*
> + * Starting from the first element in this bin, go forward
> + * in time until you find a trace entry that satisfies the
> + * condition defined by plugin_check_pid.
> + */
> + entryF = ksmodel_get_entry_front(histo, bin, false,
> + kshark_match_pid, pid,
> + col, nullptr);
> +
> + /*
> + * Starting from the last element in this bin, go backward
> + * in time until you find a trace entry that satisfies the
> + * condition defined by plugin_wakeup_check_pid.
> + */
> + entryB = ksmodel_get_entry_back(histo, bin, false,
> + plugin_wakeup_match_pid, pid,
> + col, nullptr);
> +
> + if (entryB &&
> + plugin_ctx->sched_wakeup_event &&
> + entryB->event_id == plugin_ctx->sched_wakeup_event->id) {
> + wakeup_pid =
> + plugin_get_wakeup_pid_lazy(kshark_ctx, entryB);
> + if (wakeup_pid == pid) {
> + /*
> + * entryB is a sched_wakeup_event. Open a
> + * green box here.
> + */
> + openBox(&rec, graph->getBin(bin),
> + graph->getHeight() * .3);
> +
> + /* Green */
> + rec->_color = KsPlot::Color(0, 255, 0);
> + }
> + }
> +
> + if (entryF &&
> + plugin_ctx->sched_switch_event &&
> + entryF->event_id == plugin_ctx->sched_switch_event->id &&
> + entryF->pid == pid) {
> + /*
> + * entryF is sched_switch_event. Close the box and add
> + * it to the list of shapes to be ploted.
> + */
> + closeBox(&rec, graph->getBin(bin),
> + graph->getHeight() * .3,
> + shapes);
> + }
> + }
> +
> + if (rec)
> + delete rec;
> +
> + return;
> +}
> +
> +static void schedSwitchPluginDraw(struct plugin_sched_context *plugin_ctx,
> + kshark_trace_histo *histo,
> + KsPlot::Graph *graph,
> + int pid,
> + KsPlot::PlotObjList *shapes)
This is quite similar to the function above, is there a way to combine
the two? This is C++ ;-)
-- Steve
> +{
> + const kshark_entry *entryF, *entryB;
> + KsPlot::Rectangle *rec = nullptr;
> + kshark_context *kshark_ctx(NULL);
> + kshark_entry_collection *col;
> +
> + kshark_instance(&kshark_ctx);
> + col = kshark_find_data_collection(kshark_ctx->collections,
> + kshark_match_pid, pid);
> +
> + size_t nBins = graph->size();
> + for (size_t bin = 0; bin < nBins; ++bin) {
> +
> + if (ksmodel_bin_count(histo, bin) > 500)
> + continue;
> +
> + /*
> + * Starting from the first element in this bin, go forward
> + * in time until you find a trace entry that satisfies the
> + * condition defined by kshark_match_pid.
> + */
> + entryF = ksmodel_get_entry_front(histo, bin, false,
> + kshark_match_pid, pid,
> + col, nullptr);
> +
> + /*
> + * Starting from the last element in this bin, go backward
> + * in time until you find a trace entry that satisfies the
> + * condition defined by plugin_switch_check_pid.
> + */
> + entryB = ksmodel_get_entry_back(histo, bin, false,
> + plugin_switch_match_pid, pid,
> + col, nullptr);
> +
> + if (entryB && entryB->pid != pid &&
> + entryB->event_id == plugin_ctx->sched_switch_event->id) {
> + /*
> + * entryB is a sched_switch_event.
> + * Open a red box here.
> + */
> + openBox(&rec, graph->getBin(bin),
> + graph->getHeight() * .3);
> +
> + /* Red */
> + rec->_color = KsPlot::Color(255, 0, 0);
> + }
> +
> + if (entryF && entryF->pid == pid &&
> + entryF->event_id == plugin_ctx->sched_switch_event->id) {
> + /*
> + * entryF is sched_switch_event.
> + * Close the box and add it to the list
> + * of shapes to be ploted.
> + */
> + closeBox(&rec, graph->getBin(bin),
> + graph->getHeight() * .3,
> + shapes);
> + }
> + }
> +
> + if (rec)
> + delete rec;
> +
> + return;
> +}
> +
> +/**
> + * @brief Plugin's draw function.
> + *
> + * @param argv_c: A C pointer to be converted to KsCppArgV (C++ struct).
> + * @param pid: Process Id.
> + * @param draw_action: Draw action identifier.
> + *
> + * @returns True if the Pid of the entry matches the value of "pid".
> + * Otherwise false.
> + */
> +void plugin_draw(struct kshark_cpp_argv *argv_c, int pid, int draw_action)
> +{
> + if (draw_action != KSHARK_PLUGIN_TASK_DRAW || pid == 0)
> + return;
> +
> + struct plugin_sched_context *plugin_ctx =
> + plugin_sched_context_handler;
> +
> + if (!plugin_ctx)
> + return;
> +
> + KsCppArgV *argvCpp = KS_ARGV_TO_CPP(argv_c);
> +
> + schedWakeupPluginDraw(plugin_ctx, argvCpp->_histo,
> + argvCpp->_graph,
> + pid,
> + argvCpp->_shapes);
> +
> + schedSwitchPluginDraw(plugin_ctx, argvCpp->_histo,
> + argvCpp->_graph,
> + pid,
> + argvCpp->_shapes);
> +}
> diff --git a/kernel-shark-qt/src/plugins/sched_events.c b/kernel-shark-qt/src/plugins/sched_events.c
> new file mode 100644
> index 0000000..2885a22
> --- /dev/null
> +++ b/kernel-shark-qt/src/plugins/sched_events.c
> @@ -0,0 +1,302 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +
> +/*
> + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +/**
> + * @file sched_events.c
> + * @brief Plugin for Sched events.
> + */
> +
> +// C
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +// KernelShark
> +#include "plugins/sched_events.h"
> +
> +/** Plugin context instance. */
> +struct plugin_sched_context *plugin_sched_context_handler = NULL;
> +
> +static bool plugin_sched_update_context(struct kshark_context *kshark_ctx)
> +{
> + struct plugin_sched_context *plugin_ctx;
> + struct event_format *event;
> +
> + if (!plugin_sched_context_handler) {
> + plugin_sched_context_handler =
> + malloc(sizeof(*plugin_sched_context_handler));
> + }
> +
> + plugin_ctx = plugin_sched_context_handler;
> + plugin_ctx->handle = kshark_ctx->handle;
> + plugin_ctx->pevent = kshark_ctx->pevent;
> +
> + event = tep_find_event_by_name(plugin_ctx->pevent,
> + "sched", "sched_switch");
> + if (!event)
> + return false;
> +
> + plugin_ctx->sched_switch_event = event;
> + plugin_ctx->sched_switch_next_field =
> + tep_find_any_field(event, "next_pid");
> +
> + plugin_ctx->sched_switch_comm_field =
> + tep_find_field(event, "next_comm");
> +
> + event = tep_find_event_by_name(plugin_ctx->pevent,
> + "sched", "sched_wakeup");
> + if (!event)
> + return false;
> +
> + plugin_ctx->sched_wakeup_event = event;
> + plugin_ctx->sched_wakeup_pid_field =
> + tep_find_any_field(event, "pid");
> +
> + plugin_ctx->sched_wakeup_success_field =
> + tep_find_field(event, "success");
> +
> + event = tep_find_event_by_name(plugin_ctx->pevent,
> + "sched", "sched_wakeup_new");
> + if (!event)
> + return false;
> +
> + plugin_ctx->sched_wakeup_new_event = event;
> + plugin_ctx->sched_wakeup_new_pid_field =
> + tep_find_any_field(event, "pid");
> +
> + plugin_ctx->sched_wakeup_new_success_field =
> + tep_find_field(event, "success");
> +
> + return true;
> +}
> +
> +/**
> + * @brief Get the Process Id of the next scheduled task.
> + *
> + * @param record: Input location for a sched_switch record.
> + */
> +int plugin_get_next_pid(struct tep_record *record)
> +{
> + struct plugin_sched_context *plugin_ctx =
> + plugin_sched_context_handler;
> + unsigned long long val;
> +
> + tep_read_number_field(plugin_ctx->sched_switch_next_field,
> + record->data, &val);
> + return val;
> +}
> +
> +/**
> + * @brief Get the Process Id of the task being woke up.
> + *
> + * @param record: Input location for a sched_wakeup record.
> + */
> +int plugin_get_wakeup_pid(struct tep_record *record)
> +{
> + struct plugin_sched_context *plugin_ctx =
> + plugin_sched_context_handler;
> + unsigned long long val;
> +
> + tep_read_number_field(plugin_ctx->sched_wakeup_pid_field,
> + record->data, &val);
> + return val;
> +}
> +
> +static void plugin_register_command(struct kshark_context *kshark_ctx,
> + struct tep_record *record,
> + int pid)
> +{
> + struct plugin_sched_context *plugin_ctx =
> + plugin_sched_context_handler;
> + const char *comm;
> +
> + if (plugin_ctx->sched_switch_comm_field) {
> + comm = record->data +
> + plugin_ctx->sched_switch_comm_field->offset;
> + }
> +
> + if (!tep_pid_is_registered(kshark_ctx->pevent, pid))
> + tep_register_comm(kshark_ctx->pevent,
> + comm, pid);
> +}
> +
> +static int plugin_get_wakeup_new_pid(struct tep_record *record)
> +{
> + struct plugin_sched_context *plugin_ctx =
> + plugin_sched_context_handler;
> + unsigned long long val;
> +
> + tep_read_number_field(plugin_ctx->sched_wakeup_new_pid_field,
> + record->data, &val);
> +
> + return val;
> +}
> +
> +/**
> + * @brief Process Id matching function adapted for sched_wakeup and
> + * sched_wakeup_new events.
> + *
> + * @param kshark_ctx: Input location for the session context pointer.
> + * @param e: kshark_entry to be checked.
> + * @param pid: Matching condition value.
> + *
> + * @returns True if the Pid of the entry matches the value of "pid".
> + * Otherwise false.
> + */
> +bool plugin_wakeup_match_pid(struct kshark_context *kshark_ctx,
> + struct kshark_entry *e,
> + int pid)
> +{
> + struct plugin_sched_context *plugin_ctx;
> + struct tep_record *record = NULL;
> + unsigned long long val;
> + int wakeup_pid = -1;
> +
> + if (e->pid == pid)
> + return true;
> +
> + plugin_ctx = plugin_sched_context_handler;
> + if (!plugin_ctx)
> + return false;
> +
> + if (plugin_ctx->sched_wakeup_event &&
> + e->event_id == plugin_ctx->sched_wakeup_event->id) {
> + record = kshark_read_at(kshark_ctx, e->offset);
> +
> + /* We only want those that actually woke up the task. */
> + tep_read_number_field(plugin_ctx->sched_wakeup_success_field,
> + record->data, &val);
> +
> + if (val)
> + wakeup_pid = plugin_get_wakeup_pid(record);
> + }
> +
> + if (plugin_ctx->sched_wakeup_new_event &&
> + e->event_id == plugin_ctx->sched_wakeup_new_event->id) {
> + record = kshark_read_at(kshark_ctx, e->offset);
> +
> + /* We only want those that actually woke up the task. */
> + tep_read_number_field(plugin_ctx->sched_wakeup_new_success_field,
> + record->data, &val);
> +
> + if (val)
> + wakeup_pid = plugin_get_wakeup_new_pid(record);
> + }
> +
> + free(record);
> +
> + if (wakeup_pid >= 0 && wakeup_pid == pid)
> + return true;
> +
> + return false;
> +}
> +
> +/**
> + * @brief Process Id matching function adapted for sched_switch events.
> + *
> + * @param kshark_ctx: Input location for the session context pointer.
> + * @param e: kshark_entry to be checked.
> + * @param pid: Matching condition value.
> + *
> + * @returns True if the Pid of the entry matches the value of "pid".
> + * Otherwise false.
> + */
> +bool plugin_switch_match_pid(struct kshark_context *kshark_ctx,
> + struct kshark_entry *e,
> + int pid)
> +{
> + struct plugin_sched_context *plugin_ctx;
> + struct tep_record *record = NULL;
> + int switch_pid = -1;
> +
> + if (e->pid == pid)
> + return true;
> +
> + plugin_ctx = plugin_sched_context_handler;
> +
> + if (plugin_ctx->sched_switch_event &&
> + e->event_id == plugin_ctx->sched_switch_event->id) {
> + record = kshark_read_at(kshark_ctx, e->offset);
> +
> + switch_pid = tep_data_pid(plugin_ctx->pevent, record);
> + }
> +
> + free(record);
> +
> + if (switch_pid >= 0 && switch_pid == pid)
> + return true;
> +
> + return false;
> +}
> +
> +static void plugin_sched_action(struct kshark_context *kshark_ctx,
> + struct tep_record *rec,
> + struct kshark_entry *entry)
> +{
> + entry->pid = plugin_get_next_pid(rec);
> + plugin_register_command(kshark_ctx, rec, entry->pid);
> +}
> +
> +static void plugin_sched_load()
> +{
> + struct kshark_context *kshark_ctx = NULL;
> + struct plugin_sched_context *plugin_ctx;
> +
> + kshark_instance(&kshark_ctx);
> +
> + if (!plugin_sched_update_context(kshark_ctx)) {
> + free(plugin_sched_context_handler);
> + plugin_sched_context_handler = NULL;
> + return;
> + }
> +
> + plugin_ctx = plugin_sched_context_handler;
> +
> + kshark_register_event_handler(&kshark_ctx->event_handlers,
> + plugin_ctx->sched_switch_event->id,
> + plugin_sched_action,
> + plugin_draw);
> +}
> +
> +static void plugin_sched_unload()
> +{
> + struct kshark_context *kshark_ctx = NULL;
> + struct plugin_sched_context *plugin_ctx;
> +
> + if (!plugin_sched_context_handler)
> + return;
> +
> + plugin_ctx = plugin_sched_context_handler;
> + kshark_instance(&kshark_ctx);
> +
> + if (kshark_ctx) {
> + kshark_unregister_event_handler(&kshark_ctx->event_handlers,
> + plugin_ctx->sched_switch_event->id,
> + plugin_sched_action,
> + plugin_draw);
> + }
> +
> + free(plugin_ctx);
> + plugin_sched_context_handler = NULL;
> +}
> +
> +/** Load this plugin. */
> +void KSHARK_PLUGIN_LOADER()
> +{
> + plugin_sched_load();
> +}
> +
> +/** Reload this plugin. */
> +void KSHARK_PLUGIN_RELOADER()
> +{
> + plugin_sched_unload();
> + plugin_sched_load();
> +}
> +
> +/** Unload this plugin. */
> +void KSHARK_PLUGIN_UNLOADER()
> +{
> + plugin_sched_unload();
> +}
> diff --git a/kernel-shark-qt/src/plugins/sched_events.h b/kernel-shark-qt/src/plugins/sched_events.h
> new file mode 100644
> index 0000000..d0c125a
> --- /dev/null
> +++ b/kernel-shark-qt/src/plugins/sched_events.h
> @@ -0,0 +1,79 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +/**
> + * @file sched_events.h
> + * @brief Plugin for Sched events.
> + */
> +
> +#ifndef _KS_PLUGIN_SHED_H
> +#define _KS_PLUGIN_SHED_H
> +
> +// trace-cmd
> +#include "event-parse.h"
> +
> +// KernelShark
> +#include "libkshark.h"
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/** Structure representing a plugin-specific context. */
> +struct plugin_sched_context {
> + /** Input handle for the trace data file. */
> + struct tracecmd_input *handle;
> +
> + /** Page event used to parse the page. */
> + struct tep_handle *pevent;
> +
> + /** Pointer to the sched_switch_event object. */
> + struct event_format *sched_switch_event;
> +
> + /** Pointer to the sched_switch_next_field format descriptor. */
> + struct format_field *sched_switch_next_field;
> +
> + /** Pointer to the sched_switch_comm_field format descriptor. */
> + struct format_field *sched_switch_comm_field;
> +
> + /** Pointer to the sched_wakeup_event object. */
> + struct event_format *sched_wakeup_event;
> +
> + /** Pointer to the sched_wakeup_pid_field format descriptor. */
> + struct format_field *sched_wakeup_pid_field;
> +
> + /** Pointer to the sched_wakeup_success_field format descriptor. */
> + struct format_field *sched_wakeup_success_field;
> +
> + /** Pointer to the sched_wakeup_new_event object. */
> + struct event_format *sched_wakeup_new_event;
> +
> + /** Pointer to the sched_wakeup_new_pid_field format descriptor. */
> + struct format_field *sched_wakeup_new_pid_field;
> +
> + /**
> + * Pointer to the sched_wakeup_new_success_field format descriptor.
> + */
> + struct format_field *sched_wakeup_new_success_field;
> +};
> +
> +int plugin_get_next_pid(struct tep_record *record);
> +
> +int plugin_get_wakeup_pid(struct tep_record *record);
> +
> +bool plugin_wakeup_match_pid(struct kshark_context *kshark_ctx,
> + struct kshark_entry *e, int pid);
> +
> +bool plugin_switch_match_pid(struct kshark_context *kshark_ctx,
> + struct kshark_entry *e, int pid);
> +
> +void plugin_draw(struct kshark_cpp_argv *argv, int pid, int draw_action);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
next prev parent reply other threads:[~2018-08-30 21:41 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-29 16:42 [PATCH 0/7] The infrastructure for plugins used by the Qt-based Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 1/7] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
2018-08-29 20:12 ` Steven Rostedt
2018-08-29 20:17 ` Steven Rostedt
2018-08-29 20:32 ` Steven Rostedt
2018-08-30 11:45 ` Yordan Karadzhov (VMware)
2018-08-30 16:17 ` Steven Rostedt
2018-08-29 16:42 ` [PATCH 2/7] kernel-shark-qt: Add Plugin event handlers to session Yordan Karadzhov (VMware)
2018-08-30 2:08 ` Steven Rostedt
2018-08-29 16:42 ` [PATCH 3/7] kernel-shark-qt: Add C++/C conversion for args of a plugin draw function Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 4/7] kernel-shark-qt: Make kshark_read_at() non-static Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 5/7] kernel-shark-qt: Add src/plugins dir. to hold the source code of the plugins Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 6/7] kernel-shark-qt: Tell Doxygen to enter ../src/plugins/ Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 7/7] kernel-shark-qt: Add a plugin for sched events Yordan Karadzhov (VMware)
2018-08-30 2:43 ` Steven Rostedt
2018-08-30 11:48 ` Yordan Karadzhov (VMware)
2018-08-30 11:49 ` Yordan Karadzhov (VMware)
2018-08-30 14:12 ` Steven Rostedt
2018-08-30 11:51 ` Yordan Karadzhov (VMware)
2018-08-30 14:13 ` Steven Rostedt
2018-08-30 14:50 ` Steven Rostedt
2018-08-30 17:38 ` Steven Rostedt [this message]
2018-08-29 16:49 ` [PATCH 0/7] Add infrastructure for plugins Yordan Karadzhov (VMware)
-- strict thread matches above, loose matches on Subject: below --
2018-09-04 15:52 Yordan Karadzhov (VMware)
2018-09-04 15:52 ` [PATCH 7/7] kernel-shark-qt: Add a plugin for sched events Yordan Karadzhov (VMware)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180830133832.657a8eab@gandalf.local.home \
--to=rostedt@goodmis.org \
--cc=linux-trace-devel@vger.kernel.org \
--cc=y.karadz@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).