diff mbox series

[v2] fstests: add basic ftrace support

Message ID 20210603062113.133326-1-wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series [v2] fstests: add basic ftrace support | expand

Commit Message

Qu Wenruo June 3, 2021, 6:21 a.m. UTC
Sometimes developers want trace dump for certain test cases.

Normally I just add "trace-cmd" calls in "check", but it would be much
better to let fstests to support ftrace dumping.

This patchset will add basic ftrace dumping support by:

- Clear all buffers before running each test
- Start tracing before running each test
- End tracing after test finished
- Copy the trace to "$seqres.trace" if needed
  The condition is either:
  * $KEEP_TRACE environment is set to "yes"
  * The test case failed

Currently we only support the main ftrace buffer, but all supporting
functions have support for ftrace instances, for later expansion.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
Changelog:
v2:
- Add explanation in "common/config" for how to use it
- Make variables local
- Don't create the instance when clearing buffers
---
 check         | 12 +++++++-
 common/config |  8 +++++
 common/ftrace | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
 common/rc     |  1 +
 4 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 common/ftrace

Comments

Dave Chinner June 4, 2021, 2:35 a.m. UTC | #1
On Thu, Jun 03, 2021 at 02:21:13PM +0800, Qu Wenruo wrote:
> Sometimes developers want trace dump for certain test cases.
> 
> Normally I just add "trace-cmd" calls in "check", but it would be much
> better to let fstests to support ftrace dumping.
> 
> This patchset will add basic ftrace dumping support by:
> 
> - Clear all buffers before running each test
> - Start tracing before running each test
> - End tracing after test finished
> - Copy the trace to "$seqres.trace" if needed
>   The condition is either:
>   * $KEEP_TRACE environment is set to "yes"
>   * The test case failed
> 
> Currently we only support the main ftrace buffer, but all supporting
> functions have support for ftrace instances, for later expansion.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> Changelog:
> v2:
> - Add explanation in "common/config" for how to use it
> - Make variables local
> - Don't create the instance when clearing buffers
> ---
>  check         | 12 +++++++-
>  common/config |  8 +++++
>  common/ftrace | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  common/rc     |  1 +
>  4 files changed, 103 insertions(+), 1 deletion(-)
>  create mode 100644 common/ftrace
> 
> diff --git a/check b/check
> index ba192042..0a09dcf9 100755
> --- a/check
> +++ b/check
> @@ -801,7 +801,7 @@ function run_section()
>  		fi
>  
>  		# really going to try and run this one
> -		rm -f $seqres.out.bad
> +		rm -f $seqres.out.bad $seqres.trace
>  
>  		# check if we really should run it
>  		_expunge_test $seqnum
> @@ -839,6 +839,10 @@ function run_section()
>  		# to be reported for each test
>  		(echo 1 > $DEBUGFS_MNT/clear_warn_once) > /dev/null 2>&1
>  
> +		# Clear previous trace and start new trace
> +		_clear_trace_buffers
> +		_start_trace

So how does one enable all 500+ xfs tracepoints for this? Or just
some subset? i.e. how do we pass it a list of events like we do
trace-cmd?  IOWs, for this to be actually useful as a replacement
for trace-cmd, it has to be able to replace invocations like this:

# trace-cmd record -e xfs_i*lock* -e xfs_buf* -e printk -e iomap* ....

which is how I use trace-cmd 99.9% of the time I'm debugging fstests
using tracepoints.

Next: some tests will generate gigabytes of trace data on XFS. I'm
not joking here - I regularly am looking for single traces in an
output file that contains tens of millions of events in it. Having
fstests run with tracing enabled is going to rapidly cause ENOSPC
problems on test machines, and that's going to cause test harness
issues...

Hence I don't think that unilaterally turning on tracing is a good
idea. I think it should only run if we set a value in the config
section for the test run. This allows a user to define two identical
test sections except one has "ENABLE_TRACE=true" in it and the other
doesn't. Hence they can run:

# check -s xfs -g auto

to get a normal, non-traced run done. Then, for all the failures
reported, run:

# check -s xfs_trace <trace specification> <failed tests>

and get those tests run with tracing enabled instead of running

# trace-cmd record <trace specification> check -s xfs <failed tests>

Finally, I also don't want fstests perturbing whatever tracing I'm
doing externally to fstests, so being having it enable tracing only
when I want it to enable tracing is somewhat important...

> +#                   NOTE: to dump ftrace buffer one needs to enable ftrace
> +#                   events or add custom trace_printk() into the fs code.
> +#                   And since fstest will clear buffer before running one
> +#                   test case, existing trace-cmd can be interrupted.

trace_printk is only a small part of the tracing I use with
trace-cmd. If we can't configure trace event output through this
interface, then it's really not a replacement for using trace-cmd...

Cheers,

Dave.
Qu Wenruo June 4, 2021, 2:45 a.m. UTC | #2
On 2021/6/4 上午10:35, Dave Chinner wrote:
> On Thu, Jun 03, 2021 at 02:21:13PM +0800, Qu Wenruo wrote:
>> Sometimes developers want trace dump for certain test cases.
>>
>> Normally I just add "trace-cmd" calls in "check", but it would be much
>> better to let fstests to support ftrace dumping.
>>
>> This patchset will add basic ftrace dumping support by:
>>
>> - Clear all buffers before running each test
>> - Start tracing before running each test
>> - End tracing after test finished
>> - Copy the trace to "$seqres.trace" if needed
>>    The condition is either:
>>    * $KEEP_TRACE environment is set to "yes"
>>    * The test case failed
>>
>> Currently we only support the main ftrace buffer, but all supporting
>> functions have support for ftrace instances, for later expansion.
>>
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>> Changelog:
>> v2:
>> - Add explanation in "common/config" for how to use it
>> - Make variables local
>> - Don't create the instance when clearing buffers
>> ---
>>   check         | 12 +++++++-
>>   common/config |  8 +++++
>>   common/ftrace | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>   common/rc     |  1 +
>>   4 files changed, 103 insertions(+), 1 deletion(-)
>>   create mode 100644 common/ftrace
>>
>> diff --git a/check b/check
>> index ba192042..0a09dcf9 100755
>> --- a/check
>> +++ b/check
>> @@ -801,7 +801,7 @@ function run_section()
>>   		fi
>>   
>>   		# really going to try and run this one
>> -		rm -f $seqres.out.bad
>> +		rm -f $seqres.out.bad $seqres.trace
>>   
>>   		# check if we really should run it
>>   		_expunge_test $seqnum
>> @@ -839,6 +839,10 @@ function run_section()
>>   		# to be reported for each test
>>   		(echo 1 > $DEBUGFS_MNT/clear_warn_once) > /dev/null 2>&1
>>   
>> +		# Clear previous trace and start new trace
>> +		_clear_trace_buffers
>> +		_start_trace
> 
> So how does one enable all 500+ xfs tracepoints for this? Or just
> some subset? i.e. how do we pass it a list of events like we do
> trace-cmd?  IOWs, for this to be actually useful as a replacement
> for trace-cmd, it has to be able to replace invocations like this:
> 
> # trace-cmd record -e xfs_i*lock* -e xfs_buf* -e printk -e iomap* ....

That's not a big problem, you can do the same thing just using tracefs 
interface, without invovling trace-cmd at all.

For your above case, you can do the same thing without trace_cmd at all:

# cat ${tracefs}/available_events | grep xfs_i*lock >> \
   ${tracefs}/set_event
# cat ${tracefs}/available_events | grep xfs_buf* >> \
   ${tracefs}/set_event
# cat ${tracefs}/available_events | grep iomap* >> \
   ${tracefs}/set_event
# cat ${tracefs}/available_events | grep printk >> \
   ${tracefs}/set_event

> 
> which is how I use trace-cmd 99.9% of the time I'm debugging fstests
> using tracepoints.

I don't bevelive above commands can be hard to use, although it's indeed 
a little complex than trace-cmd.

> 
> Next: some tests will generate gigabytes of trace data on XFS. I'm
> not joking here

That's exactly why I use custom trace_printk() to filter out certain 
events, and only print what I care.

> - I regularly am looking for single traces in an
> output file that contains tens of millions of events in it. Having
> fstests run with tracing enabled is going to rapidly cause ENOSPC
> problems on test machines, and that's going to cause test harness
> issues...
> 
> Hence I don't think that unilaterally turning on tracing is a good
> idea. I think it should only run if we set a value in the config
> section for the test run. This allows a user to define two identical
> test sections except one has "ENABLE_TRACE=true" in it and the other
> doesn't. Hence they can run:
> 
> # check -s xfs -g auto

And in the expected use case, trace is only used to test certain 
failure, not to do a full test run.
It would only make things miserably slow and make your storage explode.

But we still need to clear/start/end the events for whatever test cases 
that is going to be executed.

> 
> to get a normal, non-traced run done. Then, for all the failures
> reported, run:
> 
> # check -s xfs_trace <trace specification> <failed tests>
> 
> and get those tests run with tracing enabled instead of running
> 
> # trace-cmd record <trace specification> check -s xfs <failed tests>
> 
> Finally, I also don't want fstests perturbing whatever tracing I'm
> doing externally to fstests, so being having it enable tracing only
> when I want it to enable tracing is somewhat important...
> 
>> +#                   NOTE: to dump ftrace buffer one needs to enable ftrace
>> +#                   events or add custom trace_printk() into the fs code.
>> +#                   And since fstest will clear buffer before running one
>> +#                   test case, existing trace-cmd can be interrupted.
> 
> trace_printk is only a small part of the tracing I use with
> trace-cmd. If we can't configure trace event output through this
> interface, then it's really not a replacement for using trace-cmd...

I mean, if you can use trace-cmd, I see now reason you can't pack your 
trace events into a small script to enable it before running the tests.

Or is trace-cmd really making us forget how to manually setup ftrace 
evetnts?

Thanks,
Qu

> 
> Cheers,
> 
> Dave.
>
Darrick J. Wong June 4, 2021, 4:30 p.m. UTC | #3
On Fri, Jun 04, 2021 at 10:45:52AM +0800, Qu Wenruo wrote:
> 
> 
> On 2021/6/4 上午10:35, Dave Chinner wrote:
> > On Thu, Jun 03, 2021 at 02:21:13PM +0800, Qu Wenruo wrote:
> > > Sometimes developers want trace dump for certain test cases.
> > > 
> > > Normally I just add "trace-cmd" calls in "check", but it would be much
> > > better to let fstests to support ftrace dumping.
> > > 
> > > This patchset will add basic ftrace dumping support by:
> > > 
> > > - Clear all buffers before running each test
> > > - Start tracing before running each test
> > > - End tracing after test finished
> > > - Copy the trace to "$seqres.trace" if needed
> > >    The condition is either:
> > >    * $KEEP_TRACE environment is set to "yes"
> > >    * The test case failed
> > > 
> > > Currently we only support the main ftrace buffer, but all supporting
> > > functions have support for ftrace instances, for later expansion.
> > > 
> > > Signed-off-by: Qu Wenruo <wqu@suse.com>
> > > ---
> > > Changelog:
> > > v2:
> > > - Add explanation in "common/config" for how to use it
> > > - Make variables local
> > > - Don't create the instance when clearing buffers
> > > ---
> > >   check         | 12 +++++++-
> > >   common/config |  8 +++++
> > >   common/ftrace | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > >   common/rc     |  1 +
> > >   4 files changed, 103 insertions(+), 1 deletion(-)
> > >   create mode 100644 common/ftrace
> > > 
> > > diff --git a/check b/check
> > > index ba192042..0a09dcf9 100755
> > > --- a/check
> > > +++ b/check
> > > @@ -801,7 +801,7 @@ function run_section()
> > >   		fi
> > >   		# really going to try and run this one
> > > -		rm -f $seqres.out.bad
> > > +		rm -f $seqres.out.bad $seqres.trace
> > >   		# check if we really should run it
> > >   		_expunge_test $seqnum
> > > @@ -839,6 +839,10 @@ function run_section()
> > >   		# to be reported for each test
> > >   		(echo 1 > $DEBUGFS_MNT/clear_warn_once) > /dev/null 2>&1
> > > +		# Clear previous trace and start new trace
> > > +		_clear_trace_buffers
> > > +		_start_trace
> > 
> > So how does one enable all 500+ xfs tracepoints for this? Or just
> > some subset? i.e. how do we pass it a list of events like we do
> > trace-cmd?  IOWs, for this to be actually useful as a replacement
> > for trace-cmd, it has to be able to replace invocations like this:
> > 
> > # trace-cmd record -e xfs_i*lock* -e xfs_buf* -e printk -e iomap* ....
> 
> That's not a big problem, you can do the same thing just using tracefs
> interface, without invovling trace-cmd at all.
> 
> For your above case, you can do the same thing without trace_cmd at all:
> 
> # cat ${tracefs}/available_events | grep xfs_i*lock >> \
>   ${tracefs}/set_event
> # cat ${tracefs}/available_events | grep xfs_buf* >> \
>   ${tracefs}/set_event
> # cat ${tracefs}/available_events | grep iomap* >> \
>   ${tracefs}/set_event
> # cat ${tracefs}/available_events | grep printk >> \
>   ${tracefs}/set_event

This is **much** more work than a single trace-cmd.  Tools like
trace-cmd exist to simplify configuring complex functionality.  You can
stubbornly insist that manually fiddling around in tracefs is the end
all solution for you, but you don't get to break the entire community's
ability to use cli wrappers.

Dave and I are /not/ going to retool our entire workflows just so you
can break trace-cmd (and any other tools that use ftrace/perf
monitoring) while offering nothing even close to being a replacement.

I do not consent to disrupting well-established tracing tools.  You
rejected my earlier suggestion, so

NAK.

--D

> 
> > 
> > which is how I use trace-cmd 99.9% of the time I'm debugging fstests
> > using tracepoints.
> 
> I don't bevelive above commands can be hard to use, although it's indeed a
> little complex than trace-cmd.
> 
> > 
> > Next: some tests will generate gigabytes of trace data on XFS. I'm
> > not joking here
> 
> That's exactly why I use custom trace_printk() to filter out certain events,
> and only print what I care.
> 
> > - I regularly am looking for single traces in an
> > output file that contains tens of millions of events in it. Having
> > fstests run with tracing enabled is going to rapidly cause ENOSPC
> > problems on test machines, and that's going to cause test harness
> > issues...
> > 
> > Hence I don't think that unilaterally turning on tracing is a good
> > idea. I think it should only run if we set a value in the config
> > section for the test run. This allows a user to define two identical
> > test sections except one has "ENABLE_TRACE=true" in it and the other
> > doesn't. Hence they can run:
> > 
> > # check -s xfs -g auto
> 
> And in the expected use case, trace is only used to test certain failure,
> not to do a full test run.
> It would only make things miserably slow and make your storage explode.
> 
> But we still need to clear/start/end the events for whatever test cases that
> is going to be executed.
> 
> > 
> > to get a normal, non-traced run done. Then, for all the failures
> > reported, run:
> > 
> > # check -s xfs_trace <trace specification> <failed tests>
> > 
> > and get those tests run with tracing enabled instead of running
> > 
> > # trace-cmd record <trace specification> check -s xfs <failed tests>
> > 
> > Finally, I also don't want fstests perturbing whatever tracing I'm
> > doing externally to fstests, so being having it enable tracing only
> > when I want it to enable tracing is somewhat important...
> > 
> > > +#                   NOTE: to dump ftrace buffer one needs to enable ftrace
> > > +#                   events or add custom trace_printk() into the fs code.
> > > +#                   And since fstest will clear buffer before running one
> > > +#                   test case, existing trace-cmd can be interrupted.
> > 
> > trace_printk is only a small part of the tracing I use with
> > trace-cmd. If we can't configure trace event output through this
> > interface, then it's really not a replacement for using trace-cmd...
> 
> I mean, if you can use trace-cmd, I see now reason you can't pack your trace
> events into a small script to enable it before running the tests.
> 
> Or is trace-cmd really making us forget how to manually setup ftrace
> evetnts?
> 
> Thanks,
> Qu
> 
> > 
> > Cheers,
> > 
> > Dave.
> > 
>
Dave Chinner June 4, 2021, 10:44 p.m. UTC | #4
On Fri, Jun 04, 2021 at 10:45:52AM +0800, Qu Wenruo wrote:
> > So how does one enable all 500+ xfs tracepoints for this? Or just
> > some subset? i.e. how do we pass it a list of events like we do
> > trace-cmd?  IOWs, for this to be actually useful as a replacement
> > for trace-cmd, it has to be able to replace invocations like this:
> > 
> > # trace-cmd record -e xfs_i*lock* -e xfs_buf* -e printk -e iomap* ....
> 
> That's not a big problem, you can do the same thing just using tracefs
> interface, without invovling trace-cmd at all.
> 
> For your above case, you can do the same thing without trace_cmd at all:
> 
> # cat ${tracefs}/available_events | grep xfs_i*lock >> \
>   ${tracefs}/set_event
> # cat ${tracefs}/available_events | grep xfs_buf* >> \
>   ${tracefs}/set_event
> # cat ${tracefs}/available_events | grep iomap* >> \
>   ${tracefs}/set_event
> # cat ${tracefs}/available_events | grep printk >> \
>   ${tracefs}/set_event

....

You forgot that now I have to turn all the events off again
manually. And if the script crashes and doesn't clean up, then I've
got to do that manually.

Talk about going back to the dark ages....

> I mean, if you can use trace-cmd, I see now reason you can't pack your trace
> events into a small script to enable it before running the tests.

The whole point of using tools like perf and trace-cmd is so we
don't need to know how the underlying mechanisms work, and we don't
have to relearn this crap every time the developers decide they are
going to change how it works.

> Or is trace-cmd really making us forget how to manually setup ftrace
> evetnts?

You have got to be joking, right?

The whole point of trace-cmd and perf existing is so that nobody
except the developers of those tools need to know how the complex,
obscure, whacky low level kernel interfaces work. Nor do people have
to keep up with how they change from kernel to kernel, because the
tools abstract all this bullshit away from the user.

I forgot about that interface when trace-cmd was first written
(2009, IIRC). IOWs, I haven't used the low level tracing interfaces
at all for over a decade because it's an utter PITA to use.

Can you imaging saying to another developer "we don't need a mkfs
command because I can write the structures direct to the block
device myself!". It doesn't make much sense, does it? Yet that's
pretty much exactly what you are saying here....

So, no, I don't think poking at low level tracing interfaces inside
fstests is a good idea, especially as it also requires wrapping
fstests in more scripts to control it. Just use trace-cmd to control
trace recording like everyone else already does.

Cheers,

Dave.
diff mbox series

Patch

diff --git a/check b/check
index ba192042..0a09dcf9 100755
--- a/check
+++ b/check
@@ -801,7 +801,7 @@  function run_section()
 		fi
 
 		# really going to try and run this one
-		rm -f $seqres.out.bad
+		rm -f $seqres.out.bad $seqres.trace
 
 		# check if we really should run it
 		_expunge_test $seqnum
@@ -839,6 +839,10 @@  function run_section()
 		# to be reported for each test
 		(echo 1 > $DEBUGFS_MNT/clear_warn_once) > /dev/null 2>&1
 
+		# Clear previous trace and start new trace
+		_clear_trace_buffers
+		_start_trace
+
 		if [ "$DUMP_OUTPUT" = true ]; then
 			_run_seq 2>&1 | tee $tmp.out
 			# Because $? would get tee's return code
@@ -848,6 +852,11 @@  function run_section()
 			sts=$?
 		fi
 
+		_end_trace
+		if [ "$KEEP_TRACE" == "yes" ]; then
+			_copy_trace "$seqres.trace"
+		fi
+
 		if [ -f core ]; then
 			_dump_err_cont "[dumped core]"
 			mv core $RESULT_BASE/$seqnum.core
@@ -932,6 +941,7 @@  function run_section()
 
 	# make sure we record the status of the last test we ran.
 	if $err ; then
+		_copy_trace "$seqres.trace"
 		bad="$bad $seqnum"
 		n_bad=`expr $n_bad + 1`
 		tc_status="fail"
diff --git a/common/config b/common/config
index ad1c9eb0..4dec2bfa 100644
--- a/common/config
+++ b/common/config
@@ -25,6 +25,14 @@ 
 # KEEP_DMESG -      whether to keep all dmesg for each test case.
 #                   yes: keep all dmesg
 #                   no: only keep dmesg with error/warning (default)
+# KEEP_TRACE -	    whether to keep all non-empty ftrace buffer for each test case.
+#                   yes: keep all non-empty ftrace buffer
+#                   no: only keep non-empty ftrace buffer when the test fails (default)
+#
+#                   NOTE: to dump ftrace buffer one needs to enable ftrace
+#                   events or add custom trace_printk() into the fs code.
+#                   And since fstest will clear buffer before running one
+#                   test case, existing trace-cmd can be interrupted.
 #
 # - These can be added to $HOST_CONFIG_DIR (witch default to ./config)
 #   below or a separate local configuration file can be used (using
diff --git a/common/ftrace b/common/ftrace
new file mode 100644
index 00000000..9eec0f53
--- /dev/null
+++ b/common/ftrace
@@ -0,0 +1,83 @@ 
+# SPDX-License-Identifier: GPL-2.0
+#
+# Common ftrace related helpers
+#
+
+TRACE_DIR="/sys/kernel/debug/tracing"
+
+_clear_trace_buffers()
+{
+	if [ ! -d "${TRACE_DIR}" ]; then
+		return
+	fi
+
+	# Clear the main buffer
+	echo 0 > "${TRACE_DIR}/trace"
+
+	# Clear each instance buffer
+	for i in $(ls "${TRACE_DIR}/instances"); do
+		echo 0 > "${i}/trace"
+	done
+}
+
+_start_trace()
+{
+	local instance=$1
+
+	if [ ! -d "${TRACE_DIR}" ]; then
+		return
+	fi
+
+	if [ -z "${instance}" ]; then
+		echo 1 > "${TRACE_DIR}/tracing_on"
+	else
+		mkdir -p "${TRACE_DIR}/instances/${instance}"
+		echo 1 > "${TRACE_DIR}/instances/${instance}/tracing_on"
+	fi
+}
+
+_end_trace()
+{
+	local instance=$1
+
+	if [ ! -d "${TRACE_DIR}" ]; then
+		return
+	fi
+
+	if [ -z "${instance}" ]; then
+		echo 0 > "${TRACE_DIR}/tracing_on"
+	elif [ -d "${TRACE_DIR}/instances/${instance}" ]; then
+		echo 0 > "${TRACE_DIR}/instances/${instance}/tracing_on"
+	fi
+}
+
+_remove_empty_trace()
+{
+	local file="$1"
+
+	if [ ! -f "$file" ]; then
+		return
+	fi
+
+	if [ -z "$(head -n 15 $file | sed '/^#/d')" ]; then
+		rm $file
+	fi
+}
+
+_copy_trace()
+{
+	local dest="$1"
+	local instance="$2"
+
+	if [ ! -d "${TRACE_DIR}" ]; then
+		return
+	fi
+
+	if [ -z "${instance}" ]; then
+		cp "${TRACE_DIR}/trace" "$dest"
+	elif [ -d "${TRACE_DIR}/instances/${instance}" ]; then
+		cp "${TRACE_DIR}/instances/${instance}/trace" "$dest"
+	fi
+
+	_remove_empty_trace "$dest"
+}
diff --git a/common/rc b/common/rc
index a0aa7300..d828dca8 100644
--- a/common/rc
+++ b/common/rc
@@ -3,6 +3,7 @@ 
 # Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
 
 . common/config
+. common/ftrace
 
 BC=$(which bc 2> /dev/null) || BC=