Closed tdi2004 closed 4 years ago
Hi @tdi2004,
Could you:
I tried with 84abeef7d9f2f5cded36dcfc127b3f33db89ea57 and the following but could not reproduce your issue:
fio --rwmixread=50 --numjobs=1 --rw=randrw --exitall_on_error=1 --runtime=1d --time_based=1 --size=10M --name=1 --directory=1 --name=2 --directory=2
Hi @sitsofe ,
# ~/fio-fio-3.21/fio --rwmixread=50 --numjobs=1 --exitall_on_error=1 --runtime=30s --time_based=1 --size=10M --name=LV1 --directory=/mnt1/LV1 --name=LV2 --directory=/mnt1/LV2
LV1: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
LV2: (g=1): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
fio-3.21
Starting 2 processes
The following output line pointed me to the conclusion, that fio now starts the jobs on various directories sequentially (instead of parallel, like it did before):
Jobs: 1 (f=1): [R(1),P(1)][4.9%][r=1270MiB/s][r=325k IOPS][eta 00m:58s]
=> almost 60s = 2*30s and after 60s both directories had been treated by fio for 30 seconds. So, the parallel execution doesn't work with a commandline invocation either.
@tdi2004 ,
I still can't reproduce what you're seeing but I think the job can be minimised further. Let's check a few things:
fio --runtime=5 --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2
--debug=process --output-format=json
to the above and attach the full output that is produced to this issue, for example:
fio --debug=process --output-format=json --runtime=5 --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2
Hi @tdi2004,
unfortunately I'm also not able to reproduce the behaviour you're describing. Using git tag fio-3.21 I get the following output:
time fio --rwmixread=50 --numjobs=1 --exitall_on_error=1 --runtime=30s --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2 --rw=randrw
1: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
2: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
Runtime is, as you expect, roughly 30s, so the jobs do infact run in parallel. What I noticed is that your jobs run in different groups (notice the g= in parentheses at the beginning of each line), where your jobs run in different groups. I have no idea why that is … yet :)
Edit: I also tested current master g5c79. Result: "Works for me". (Although that probably doesn't help much.)
# ~/fio-fio-3.21/fio --runtime=5 --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2
ran a job on /tmp/1 for 5s when finished, it ran a another job on /tmp/2 for 5s. Jobs were not executed in parallel.
# ~/fio-fio-3.21/fio --debug=process --output-format=json --runtime=5 --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2 > fio.log
attaching fio.log
fio.log
Runtime is, as you expect, roughly 30s,
Not here. That's the culprit. For me it is 60s. My architecture is s390x - I can't imagine, that the forking stuff is architecture dependent.
time ~/fio-fio-3.21/fio --rwmixread=50 --numjobs=1 --exitall_on_error=1 --runtime=30s --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2 --rw=randrw --output=/dev/null
1: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
Jobs: 1 (f=1): [_(1),m(1)][100.0%][r=20.1MiB/s,w=20.4MiB/s][r=5152,w=5222 IOPS][eta 00m:00s]
real 1m1.059s
user 0m1.391s
sys 0m5.880s
Ah, I was about to ask about your compiler/architecture. I was expecting Linux/x86_64.
@sitsofe The log showed that stonewall is set, which shouldn't be set. I suspect that the issue has to do with cconv, because the value is 16 bit. There might be something funky going on. 64402a8 changed the offset/alignment of top->stonewall.
@hannesweisbach good sleuthing. The type of stonewall is FIO_OPT_STR_SET and the type of exit_what is FIO_OPT_STR too. I wonder if the option parsing is writing over the adjacent variable?
Comping with
CC=clang ./configure --disable-optimizations --extra-cflags="-fsanitize=memory -fno-omit-frame-pointer -g" && make -j 8
then running
./fio --debug=all --runtime=5 --time_based=1 --size=10M --name=1 --directory=/tmp/1 --name=2 --directory=/tmp/2```
stopped with the following error:
fio: set all debug options
==9921==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x54212c in parse_cmd_line /fio/init.c:2659:35
#1 0x549cfa in parse_options /fio/init.c:2975:14
#2 0x8b9b9d in main /fio/fio.c:42:6
#3 0x7ff3af8cb0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#4 0x42698d in _start (/fio/fio+0x42698d)
SUMMARY: MemorySanitizer: use-of-uninitialized-value /fio/init.c:2659:35 in parse_cmd_line
Exiting
So that's a starting point... which turned out to be a dead end.
The issue should be located in int __handle_option()
.
It writes to an int pointer when it handles FIO_OPT_STR
for the exit_what
default value. It could also be an issue that FIO_OPT_STR_SET
for stonewall
now writes to other fields as well because it also uses an int pointer. If you also think this is the issue, then I can send you the patch I've already written and tested for this issue.
@sitsofe @XeS0r
I agree. Call stack is:
__handle_option()
val_store()
td_var()
the latter creates in int *
which points to an unsigned short. val_store writes to this pointer of wrong size.
I have no idea, why this isn't an issue on x86/_64.
I guess it has another member alignment or it has less impact because it's little endian. Do you want me to open a pull request?
Sure, go ahead. Although I'm not a maintainer.
@hannesweisbach x86/amd64 is notorious for quietly fixing up alignment issues at a minor speed penalty (https://stackoverflow.com/a/7517370 ).
@sitsofe Sure, int
has no alignment requirement on x86, but it's also a write of the wrong size.
@tdi2004 thanks for persevering, @hannesweisbach, @XeS0r thanks for sorting this one!
Out of idle curiosity I checked what happened before this fix by running the following
fio --exit_what=all --ioengine=null --size=1T --name=1 --name=2
This showed the jobs going into different groups and --debug=process
showed stonewall
was active. To me this proves @XeS0r's endianness theory from https://github.com/axboe/fio/issues/1065#issuecomment-674069311 because a setting of of all
inserts a value of -1 (which sets all bits to 1 in an unsigned int) and causes stonewall
to become set too due to overrun. Normally exit_what
defaults to 1 and on a big endian machine like s390x (where the least significant bit ends up in the highest address) this means it would have set exit_what
to 0 and stonewall
to 1 due to the overrun.
After the fix in fd56c235caa42870e6dc33d661514375ea95ffc5 the above no longer causes two different groups to be made and there's no stonewall output when looking through the debug.
I had hoped that additional tooling could help detect this case but it doesn't look like it:
#include <stdio.h>
#include <stddef.h>
struct st {
unsigned long long l1;
unsigned short s1;
unsigned short s2;
unsigned int i1;
} comp = {.l1 = 0, .s1 = 1, .s2 = 2, .i1 = 3};
int main(void) {
unsigned int *ip;
void *p;
p = (char *) &comp + offsetof(struct st, s1);
ip = p;
*ip = 444 << 16 | 777;
printf("Address of .s1: %p .s2: %p\n", &(comp.s1), &(comp.s2));
printf("Value of .l1: %lld .s1: %d .s2: %d i1: %d\n", comp.l1, comp.s1,
comp.s2, comp.i1);
}
https://github.com/google/sanitizers/wiki/AddressSanitizerIntraObjectOverflow suggests only limited cases are catered for when it comes to intra object overflow (e.g. within a struct). Because it also defeats the type system I suspect this would be even tougher to detect statically.
Jup. I though I was being smart using uint16_ts … going 32-bit for those options is probably the right call.
Hi @hannesweisbach, assume the following jobfile:
with commit 64402a8a7b158c1b7a778b5f2508e625a6fc6317 a change in behaviour was introduced. While older fio versions started the fio parent PID and one fio child PID per each directory to run fio on several mountpoints in parallel, this is now broken. fio runs only on the first directory specified:
It shows only one job! Previous version showed five in my case. Same for pidof: pidof fio shows only 2 (parent and one child) instead of 6 (parent and five children) killing the parent pid shows in fio, that only LV1 was used: