[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20230327174844.15305988@gandalf.local.home>
Date: Mon, 27 Mar 2023 17:48:44 -0400
From: Steven Rostedt <rostedt@...dmis.org>
To: Uladzislau Rezki <urezki@...il.com>
Cc: "Zhuo, Qiuxu" <qiuxu.zhuo@...el.com>,
"Paul E . McKenney" <paulmck@...nel.org>,
RCU <rcu@...r.kernel.org>,
"quic_neeraju@...cinc.com" <quic_neeraju@...cinc.com>,
Boqun Feng <boqun.feng@...il.com>,
Joel Fernandes <joel@...lfernandes.org>,
LKML <linux-kernel@...r.kernel.org>,
Oleksiy Avramchenko <oleksiy.avramchenko@...y.com>,
Frederic Weisbecker <frederic@...nel.org>
Subject: Re: [PATCH 1/1] Reduce synchronize_rcu() waiting time
On Tue, 21 Mar 2023 16:15:53 +0100
Uladzislau Rezki <urezki@...il.com> wrote:
> Collect traces as much as you want: XQ-DQ54:/sys/kernel/tracing # echo 1 > tracing_on; sleep 10; echo 0 > tracing_on
> Next problem is how to parse it. Of course you will not be able to parse
> megabytes of traces. For that purpose i use a special C trace parser.
> If you need an example please let me know i can show here.
Not sure if you are familiar with trace-cmd, but the above could have been:
# trace-cmd record -e rcu sleep 10
and then you get the trace.dat file, which reports as:
# trace-cmd report
If you need special parsing, there's a libtracecmd library that lets you do
all that!
https://www.trace-cmd.org/Documentation/libtracecmd/
And for parsing events:
https://www.trace-cmd.org/Documentation/libtraceevent/
Basically have:
struct my_info {
/* store state info here */
};
int main(...) {
struct tracecmd_input *handle;
struct my_info info;
char *file = argv[1];
handle = tracecmd_open(file);
tracecmd_follow_event(handle, "rcu", "rcu_batch_start",
batch_start, &info);
tracecmd_follow_event(handle, "rcu", "rcu_batch_end",
batch_end, &info);
tracecmd_follow_event(handle, "rcu", "rcu_invoke_callback",
invoke_callback, &info);
tracecmd_iterate_events(handle, NULL, 0, NULL, NULL);
tracecmd_close(handle);
}
Where it will iterate the "trace.dat" file passed it, and every time it
hits an event registered by follow_event it will call that function:
static int batch_start(struct tracecmd_input *handle, struct tep_event *event,
struct tep_record *record, int cpu, void *data)
{
struct my_info *info = data;
info->start_timestamp = record->ts;
return 0;
}
static int batch_end(struct tracecmd_input *handle, struct tep_event *event,
struct tep_record *record, int cpu, void *data)
{
struct my_info *info = data;
printf("time = %lld -> %lld\n", info->start_timestapm,
record->ts);
return 0;
}
static int invoke_callback(struct tracecmd_input *handle, struct tep_event *event,
struct tep_record *record, int cpu, void *data)
{
struct my_info *info = data;
struct tep_handle *tep = tracecmd_get_tep(handle);
static struct tep_format_field *ip_field;
unsigned long long ip;
const char *func;
int pid;
if (!ip_field)
ip_field = tep_find_field(event, "func");
tep_read_number_field(ip_field, record->data, &ip);
func = tep_find_function(tep, ip);
pid = tep_data_pid(tep, record);
if (func)
printf("Processing function %s for pid %d\n", func, pid);
else
printf("Processing address 0x%llx for pid %d\n", ip, pid);
return 0;
}
And much more ;-)
Oh, and if you just want to read the live trace without recording, you
could always use libtracefs:
https://www.trace-cmd.org/Documentation/libtracefs/
And instead of using tracecmd_follow_event() with
tracecmd_iterate_events(), you can use:
const char *systems = { "rcu" };
tep = tracefs_local_events_systems(NULL, systems);
tracefs_follow_event(tep, NULL, "rcu", "rcu_invoke_callback",
invoke_callback, &info);
and iterate the live events with:
tracefs_iterate_raw_events(tep, NULL, NULL, 0, NULL, NULL);
With the callback for this being (very similar):
static int invoke_callback(struct tep_event *event,
struct tep_record *record, int cpu, void *data)
{
struct my_info *info = data;
struct tep_handle *tep = event->tep;
static struct tep_format_field *ip_field;
unsigned long long ip;
const char *func;
int pid;
if (!ip_field)
ip_field = tep_find_field(event, "func");
tep_read_number_field(ip_field, record->data, &ip);
func = tep_find_function(tep, ip);
pid = tep_data_pid(tep, record);
if (func)
printf("Processing function %s for pid %d\n", func, pid);
else
printf("Processing address 0x%llx for pid %d\n", ip, pid);
return 0;
}
-- Steve
Powered by blists - more mailing lists