From: "Darrick J. Wong" <djwong@kernel.org>
To: Zorro Lang <zlang@redhat.com>
Cc: linux-xfs@vger.kernel.org, fstests@vger.kernel.org, guan@eryu.me
Subject: Re: [PATCH v2 2/3] misc: add duration for long soak tests
Date: Mon, 24 Apr 2023 11:27:59 -0700 [thread overview]
Message-ID: <20230424182759.GH360885@frogsfrogsfrogs> (raw)
In-Reply-To: <20230422133316.eyxebbqe5rle2ipj@zlang-mailbox>
On Sat, Apr 22, 2023 at 09:33:16PM +0800, Zorro Lang wrote:
> On Fri, Apr 14, 2023 at 05:29:49PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Make it so that test runners can schedule long soak stress test programs
> > for an exact number of seconds by setting the SOAK_DURATION config
> > variable.
> >
> > Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> > Reviewed-by: Andrey Albershteyn <aalbersh@redhat.com>
> > ---
> > v2: fix commit message
> > ---
> > check | 14 +++++++++
> > common/config | 7 ++++
> > common/fuzzy | 7 ++++
> > common/report | 1 +
> > ltp/fsstress.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++--
> > ltp/fsx.c | 50 +++++++++++++++++++++++++++++++
> > src/soak_duration.awk | 23 ++++++++++++++
> > tests/generic/476 | 5 +++
> > tests/generic/521 | 1 +
> > tests/generic/522 | 1 +
> > tests/generic/642 | 1 +
> > 11 files changed, 182 insertions(+), 6 deletions(-)
> > create mode 100644 src/soak_duration.awk
> >
> > diff --git a/check b/check
> > index e32b70d301..1d78cf27f4 100755
> > --- a/check
> > +++ b/check
> > @@ -366,6 +366,20 @@ if ! . ./common/rc; then
> > exit 1
> > fi
> >
> > +# If the test config specified a soak test duration, see if there are any
> > +# unit suffixes that need converting to an integer seconds count.
> > +if [ -n "$SOAK_DURATION" ]; then
> > + SOAK_DURATION="$(echo "$SOAK_DURATION" | \
> > + sed -e 's/^\([.0-9]*\)\([a-z]\)*/\1 \2/g' | \
> > + $AWK_PROG -f $here/src/soak_duration.awk)"
> > + if [ $? -ne 0 ]; then
> > + echo "$SOAK_DURATION"
>
> echo SOAK_DURATION=$SOAK_DURATION ?
Hmm. On nonzero return, the awk script already specified the reason
that the input was rejected, so I think this line can go away.
> > + status=1
> > + exit 1
> > + fi
> > + export SOAK_DURATION
>
> Is this necessary? As you've exported SOAK_DURATION in common/config:
>
> export SOAK_DURATION=${SOAK_DURATION:=}
You're correct, it does not need to be re-exported.
> > +fi
> > +
> > if [ -n "$subdir_xfile" ]; then
> > for d in $SRC_GROUPS $FSTYP; do
> > [ -f $SRC_DIR/$d/$subdir_xfile ] || continue
> > diff --git a/common/config b/common/config
> > index 6c8cb3a5ba..fdd0aadbeb 100644
> > --- a/common/config
> > +++ b/common/config
> > @@ -57,6 +57,13 @@ export SOAK_PROC=3 # -p option to fsstress
> > export SOAK_STRESS=10000 # -n option to fsstress
> > export SOAK_PASSES=-1 # count of repetitions of fsstress (while soaking)
> > export EMAIL=root@localhost # where auto-qa will send its status messages
> > +
> > +# For certain tests that run in tight loops, setting this variable allows the
> > +# test runner to specify exactly how long the test should continue looping.
> > +# This is independent of TIME_FACTOR. Floating point numbers are allowed, and
> > +# the unit suffixes m(inutes), h(ours), d(ays), and w(eeks) are supported.
> > +export SOAK_DURATION=${SOAK_DURATION:=}
>
> Better to describe more about the SOAK_DURATION (and TIME/LOAD_FACTOR) in
> documentation (README?). To clarify the relationship of SOAK_DURATION with
> other related parameters, and how the SOAK_DURATION works/be used.
TIME_FACTOR is not documented in the README. I'll add another patch to
do that...
> > +
> > export HOST_OPTIONS=${HOST_OPTIONS:=local.config}
> > export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
> > export BENCH_PASSES=${BENCH_PASSES:=5}
> > diff --git a/common/fuzzy b/common/fuzzy
> > index 744d9ed65d..9c04bb5318 100644
> > --- a/common/fuzzy
> > +++ b/common/fuzzy
> > @@ -1360,7 +1360,12 @@ _scratch_xfs_stress_scrub() {
> > fi
> >
> > local start="$(date +%s)"
> > - local end="$((start + (30 * TIME_FACTOR) ))"
> > + local end
> > + if [ -n "$SOAK_DURATION" ]; then
> > + end="$((start + SOAK_DURATION))"
> > + else
> > + end="$((start + (30 * TIME_FACTOR) ))"
> > + fi
> > local scrub_startat="$((start + scrub_delay))"
> > test "$scrub_startat" -gt "$((end - 10))" &&
> > scrub_startat="$((end - 10))"
> > diff --git a/common/report b/common/report
> > index be930e0b06..9bfa09ecce 100644
> > --- a/common/report
> > +++ b/common/report
> > @@ -67,6 +67,7 @@ __generate_report_vars() {
> > REPORT_VARS["CPUS"]="$(getconf _NPROCESSORS_ONLN 2>/dev/null)"
> > REPORT_VARS["MEM_KB"]="$(grep MemTotal: /proc/meminfo | awk '{print $2}')"
> > REPORT_VARS["SWAP_KB"]="$(grep SwapTotal: /proc/meminfo | awk '{print $2}')"
> > + test -n "$SOAK_DURATION" && REPORT_VARS["SOAK_DURATION"]="$SOAK_DURATION"
> >
> > test -e /sys/devices/system/node/possible && \
> > REPORT_VARS["NUMA_NODES"]="$(cat /sys/devices/system/node/possible 2>/dev/null)"
> > diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> > index e60f2da929..0dc6545448 100644
> > --- a/ltp/fsstress.c
> > +++ b/ltp/fsstress.c
> > @@ -386,6 +386,8 @@ char *execute_cmd = NULL;
> > int execute_freq = 1;
> > struct print_string flag_str = {0};
> >
> > +struct timespec deadline = { 0 };
> > +
> > void add_to_flist(int, int, int, int);
> > void append_pathname(pathname_t *, char *);
> > int attr_list_path(pathname_t *, char *, const int);
> > @@ -459,6 +461,34 @@ void sg_handler(int signum)
> > }
> > }
> >
> > +bool
> > +keep_looping(int i, int loops)
> > +{
> > + int ret;
> > +
> > + if (deadline.tv_nsec) {
> > + struct timespec now;
> > +
> > + ret = clock_gettime(CLOCK_MONOTONIC, &now);
> > + if (ret) {
> > + perror("CLOCK_MONOTONIC");
> > + return false;
> > + }
> > +
> > + return now.tv_sec <= deadline.tv_sec;
> > + }
> > +
> > + if (!loops)
> > + return true;
> > +
> > + return i < loops;
> > +}
> > +
> > +static struct option longopts[] = {
> > + {"duration", optional_argument, 0, 256},
>
> OK, we'd better to check those test cases use fsstress "-n" later, think about
> if some of them should be replaced by "--duration".
<nod> I'll update the fsstress/fsx --help screens to state that
--duration overrides -n/-N.
--D
> Thanks,
> Zorro
>
> > + { }
> > +};
> > +
> > int main(int argc, char **argv)
> > {
> > char buf[10];
> > @@ -478,13 +508,14 @@ int main(int argc, char **argv)
> > struct sigaction action;
> > int loops = 1;
> > const char *allopts = "cd:e:f:i:l:m:M:n:o:p:rRs:S:vVwx:X:zH";
> > + long long duration;
> >
> > errrange = errtag = 0;
> > umask(0);
> > nops = sizeof(ops) / sizeof(ops[0]);
> > ops_end = &ops[nops];
> > myprog = argv[0];
> > - while ((c = getopt(argc, argv, allopts)) != -1) {
> > + while ((c = getopt_long(argc, argv, allopts, longopts, NULL)) != -1) {
> > switch (c) {
> > case 'c':
> > cleanup = 1;
> > @@ -579,6 +610,26 @@ int main(int argc, char **argv)
> > case 'X':
> > execute_freq = strtoul(optarg, NULL, 0);
> > break;
> > + case 256: /* --duration */
> > + if (!optarg) {
> > + fprintf(stderr, "Specify time with --duration=\n");
> > + exit(87);
> > + }
> > + duration = strtoll(optarg, NULL, 0);
> > + if (duration < 1) {
> > + fprintf(stderr, "%lld: invalid duration\n", duration);
> > + exit(88);
> > + }
> > +
> > + i = clock_gettime(CLOCK_MONOTONIC, &deadline);
> > + if (i) {
> > + perror("CLOCK_MONOTONIC");
> > + exit(89);
> > + }
> > +
> > + deadline.tv_sec += duration;
> > + deadline.tv_nsec = 1;
> > + break;
> > case '?':
> > fprintf(stderr, "%s - invalid parameters\n",
> > myprog);
> > @@ -721,7 +772,7 @@ int main(int argc, char **argv)
> > }
> > }
> > #endif
> > - for (i = 0; !loops || (i < loops); i++)
> > + for (i = 0; keep_looping(i, loops); i++)
> > doproc();
> > #ifdef AIO
> > if(io_destroy(io_ctx) != 0) {
> > @@ -1121,6 +1172,26 @@ dirid_to_fent(int dirid)
> > return NULL;
> > }
> >
> > +bool
> > +keep_running(opnum_t opno, opnum_t operations)
> > +{
> > + int ret;
> > +
> > + if (deadline.tv_nsec) {
> > + struct timespec now;
> > +
> > + ret = clock_gettime(CLOCK_MONOTONIC, &now);
> > + if (ret) {
> > + perror("CLOCK_MONOTONIC");
> > + return false;
> > + }
> > +
> > + return now.tv_sec <= deadline.tv_sec;
> > + }
> > +
> > + return opno < operations;
> > +}
> > +
> > void
> > doproc(void)
> > {
> > @@ -1149,7 +1220,7 @@ doproc(void)
> > srandom(seed);
> > if (namerand)
> > namerand = random();
> > - for (opno = 0; opno < operations; opno++) {
> > + for (opno = 0; keep_running(opno, operations); opno++) {
> > if (execute_cmd && opno && opno % dividend == 0) {
> > if (verbose)
> > printf("%lld: execute command %s\n", opno,
> > @@ -1935,6 +2006,7 @@ usage(void)
> > printf(" -V specifies verifiable logging mode (omitting inode numbers)\n");
> > printf(" -X ncmd number of calls to the -x command (default 1)\n");
> > printf(" -H prints usage and exits\n");
> > + printf(" --duration=s run for this many seconds\n");
> > }
> >
> > void
> > diff --git a/ltp/fsx.c b/ltp/fsx.c
> > index ee4b8fe45d..761d5e467f 100644
> > --- a/ltp/fsx.c
> > +++ b/ltp/fsx.c
> > @@ -193,6 +193,8 @@ int fsx_rw(int rw, int fd, char *buf, unsigned len, unsigned offset);
> > #define fsxread(a,b,c,d) fsx_rw(READ, a,b,c,d)
> > #define fsxwrite(a,b,c,d) fsx_rw(WRITE, a,b,c,d)
> >
> > +struct timespec deadline;
> > +
> > const char *replayops = NULL;
> > const char *recordops = NULL;
> > FILE * fsxlogf = NULL;
> > @@ -2457,6 +2459,7 @@ usage(void)
> > -Z: O_DIRECT (use -R, -W, -r and -w too)\n\
> > --replay-ops opsfile: replay ops from recorded .fsxops file\n\
> > --record-ops[=opsfile]: dump ops file also on success. optionally specify ops file name\n\
> > + --duration=seconds: run for this many seconds\n\
> > fname: this filename is REQUIRED (no default)\n");
> > exit(90);
> > }
> > @@ -2739,9 +2742,33 @@ __test_fallocate(int mode, const char *mode_str)
> > #endif
> > }
> >
> > +bool
> > +keep_running(void)
> > +{
> > + int ret;
> > +
> > + if (deadline.tv_nsec) {
> > + struct timespec now;
> > +
> > + ret = clock_gettime(CLOCK_MONOTONIC, &now);
> > + if (ret) {
> > + perror("CLOCK_MONOTONIC");
> > + return false;
> > + }
> > +
> > + return now.tv_sec <= deadline.tv_sec;
> > + }
> > +
> > + if (numops == -1)
> > + return true;
> > +
> > + return numops-- != 0;
> > +}
> > +
> > static struct option longopts[] = {
> > {"replay-ops", required_argument, 0, 256},
> > {"record-ops", optional_argument, 0, 255},
> > + {"duration", optional_argument, 0, 254},
> > { }
> > };
> >
> > @@ -2753,6 +2780,7 @@ main(int argc, char **argv)
> > char logfile[PATH_MAX];
> > struct stat statbuf;
> > int o_flags = O_RDWR|O_CREAT|O_TRUNC;
> > + long long duration;
> >
> > logfile[0] = 0;
> > dname[0] = 0;
> > @@ -2950,6 +2978,26 @@ main(int argc, char **argv)
> > o_direct = O_DIRECT;
> > o_flags |= O_DIRECT;
> > break;
> > + case 254: /* --duration */
> > + if (!optarg) {
> > + fprintf(stderr, "Specify time with --duration=\n");
> > + exit(87);
> > + }
> > + duration = strtoll(optarg, NULL, 0);
> > + if (duration < 1) {
> > + fprintf(stderr, "%lld: invalid duration\n", duration);
> > + exit(88);
> > + }
> > +
> > + i = clock_gettime(CLOCK_MONOTONIC, &deadline);
> > + if (i) {
> > + perror("CLOCK_MONOTONIC");
> > + exit(89);
> > + }
> > +
> > + deadline.tv_sec += duration;
> > + deadline.tv_nsec = 1;
> > + break;
> > case 255: /* --record-ops */
> > if (optarg)
> > snprintf(opsfile, sizeof(opsfile), "%s", optarg);
> > @@ -3145,7 +3193,7 @@ main(int argc, char **argv)
> > if (xchg_range_calls)
> > xchg_range_calls = test_xchg_range();
> >
> > - while (numops == -1 || numops--)
> > + while (keep_running())
> > if (!test())
> > break;
> >
> > diff --git a/src/soak_duration.awk b/src/soak_duration.awk
> > new file mode 100644
> > index 0000000000..6c38d09b39
> > --- /dev/null
> > +++ b/src/soak_duration.awk
> > @@ -0,0 +1,23 @@
> > +#!/usr/bin/awk
> > +#
> > +# Convert time interval specifications with suffixes to an integer number of
> > +# seconds.
> > +{
> > + nr = $1;
> > + if ($2 == "" || $2 ~ /s/) # seconds
> > + ;
> > + else if ($2 ~ /m/) # minutes
> > + nr *= 60;
> > + else if ($2 ~ /h/) # hours
> > + nr *= 3600;
> > + else if ($2 ~ /d/) # days
> > + nr *= 86400;
> > + else if ($2 ~ /w/) # weeks
> > + nr *= 604800;
> > + else {
> > + printf("%s: unknown suffix\n", $2);
> > + exit 1;
> > + }
> > +
> > + printf("%d\n", nr);
> > +}
> > diff --git a/tests/generic/476 b/tests/generic/476
> > index edb0be7b50..a162cda6b1 100755
> > --- a/tests/generic/476
> > +++ b/tests/generic/476
> > @@ -33,7 +33,10 @@ _scratch_mount >> $seqres.full 2>&1
> >
> > nr_cpus=$((LOAD_FACTOR * 4))
> > nr_ops=$((25000 * nr_cpus * TIME_FACTOR))
> > -$FSSTRESS_PROG $FSSTRESS_AVOID -w -d $SCRATCH_MNT -n $nr_ops -p $nr_cpus >> $seqres.full
> > +fsstress_args=(-w -d $SCRATCH_MNT -n $nr_ops -p $nr_cpus)
> > +test -n "$SOAK_DURATION" && fsstress_args+=(--duration="$SOAK_DURATION")
> > +
> > +$FSSTRESS_PROG $FSSTRESS_AVOID "${fsstress_args[@]}" >> $seqres.full
> >
> > # success, all done
> > status=0
> > diff --git a/tests/generic/521 b/tests/generic/521
> > index cde9d44775..22dd31a8ec 100755
> > --- a/tests/generic/521
> > +++ b/tests/generic/521
> > @@ -35,6 +35,7 @@ fsx_args+=(-r $min_dio_sz)
> > fsx_args+=(-t $min_dio_sz)
> > fsx_args+=(-w $min_dio_sz)
> > fsx_args+=(-Z)
> > +test -n "$SOAK_DURATION" && fsx_args+=(--duration="$SOAK_DURATION")
> >
> > run_fsx "${fsx_args[@]}" | sed -e '/^fsx.*/d'
> >
> > diff --git a/tests/generic/522 b/tests/generic/522
> > index ae84fe04bb..f0cbcb245c 100755
> > --- a/tests/generic/522
> > +++ b/tests/generic/522
> > @@ -29,6 +29,7 @@ fsx_args+=(-N $nr_ops)
> > fsx_args+=(-p $((nr_ops / 100)))
> > fsx_args+=(-o $op_sz)
> > fsx_args+=(-l $file_sz)
> > +test -n "$SOAK_DURATION" && fsx_args+=(--duration="$SOAK_DURATION")
> >
> > run_fsx "${fsx_args[@]}" | sed -e '/^fsx.*/d'
> >
> > diff --git a/tests/generic/642 b/tests/generic/642
> > index c0e274d843..eba90903a3 100755
> > --- a/tests/generic/642
> > +++ b/tests/generic/642
> > @@ -49,6 +49,7 @@ for verb in attr_remove removefattr; do
> > done
> > args+=('-f' "setfattr=20")
> > args+=('-f' "attr_set=60") # sets larger xattrs
> > +test -n "$DURATION" && args+=(--duration="$DURATION")
> >
> > $FSSTRESS_PROG "${args[@]}" $FSSTRESS_AVOID -d $SCRATCH_MNT -n $nr_ops -p $nr_cpus >> $seqres.full
> >
> >
>
next prev parent reply other threads:[~2023-04-24 18:28 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-11 18:13 [PATCHSET 0/3] fstests: direct specification of looping test duration Darrick J. Wong
2023-04-11 18:13 ` [PATCH 1/3] generic/476: reclassify this test as a long running soak stress test Darrick J. Wong
2023-04-22 8:24 ` Zorro Lang
2023-04-24 18:17 ` Darrick J. Wong
2023-04-25 4:50 ` Zorro Lang
2023-04-11 18:13 ` [PATCH 2/3] misc: add duration for long soak tests Darrick J. Wong
2023-04-15 0:29 ` [PATCH v2 " Darrick J. Wong
2023-04-22 13:33 ` Zorro Lang
2023-04-24 18:27 ` Darrick J. Wong [this message]
2023-04-11 18:14 ` [PATCH 3/3] misc: add duration for recovery loop tests Darrick J. Wong
2023-04-23 15:09 ` Zorro Lang
2023-04-24 17:57 ` Darrick J. Wong
2023-04-13 10:48 ` [PATCHSET 0/3] fstests: direct specification of looping test duration Andrey Albershteyn
2023-04-13 14:47 ` Darrick J. Wong
2023-04-13 15:43 ` Andrey Albershteyn
2023-04-15 0:28 ` Darrick J. Wong
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=20230424182759.GH360885@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=fstests@vger.kernel.org \
--cc=guan@eryu.me \
--cc=linux-xfs@vger.kernel.org \
--cc=zlang@redhat.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