ColinIanKing / stress-ng

This is the stress-ng upstream project git repository. stress-ng will stress test a computer system in various selectable ways. It was designed to exercise various physical subsystems of a computer as well as the various operating system kernel interfaces.
https://github.com/ColinIanKing/stress-ng
GNU General Public License v2.0
1.82k stars 290 forks source link

Suggestion: Execute pread/pwrite() in parallel on a shared file descriptor #429

Closed chrfranke closed 2 months ago

chrfranke commented 2 months ago

The pread*()/pwrite*() family of functions are the only way to do parallel random accesses on the same, dup()ed or inherited file descriptor without additional locking. This leads to the following idea (sorry if I missed that something similar is already present):

Create a file and inherit its fd to multiple fork()ed processes. Each process repeatedly writes modified process specific data to a private file section and then reads and checks the other sections. One process does this with lseek()/read()/write(), all others do this with pread()/pwrite().

Could also be done with multiple threads using the same file descriptor.

Here a related comment in the source of the Cygwin POSIX emulation layer: https://cygwin.com/git/?p=newlib-cygwin.git;a=blob;f=winsup/cygwin/fhandler/disk_file.cc;h=f4c21d3#l1736

ColinIanKing commented 2 months ago

Sounds like a good idea. So if I understand this:

  1. Use Fixed Write/Read of buffer sizes say 1K
  2. open temp file, fork N children, use the same shared fd for the children for file I/O
  3. For 1..N stressor children processes, each process write/reads to say position (instance number * sizeof(buffer)) and checks the data: instances 1..N -1 use pwrite/pread instance N uses seek/write, seek/read

Additional features: 1) Make write/read size user selectable 2) Make seek position randomized (with no over-lapping between processes) 3) Make number of child processes user selectable. 4) Use pthreads instead of fork()

How a new stressor named pseekio to do this? (or any better name if you can think of one)

chrfranke commented 2 months ago

Sounds good. Other possible name: preadwrite ?

Written blocks could possibly be filled with (instance_number, file_offset, write_count) in some encoding. This allows to check that R/W ops are atomic. Instance N could seek with SEEK_CUR and then check the expected position to ensure that the previous seek position was not moved by other instances.

Another possible enhancement: Use pthreads in each fork()ed process.

ColinIanKing commented 2 months ago

preadwrite is kind of ok apart from the fact that the stressor does pwrite and then pread and the name extra options make the options really quite long in name.

I've got an initial implementation done now, but I'm now thinking of mixing the processes with 50% pthreads and 50% forked child processes. If a system does not support pthread it will do 100% forked child processes.

chrfranke commented 2 months ago

Thanks! Looks good so far and reveals a subtle bug on Cygwin.

It would be useful if the --verbose mode would provide information about processes and threads actually started by each stressor instance (also applies to other stressors with more than one process/thread per instance).

BTW, there is a useless assigment proc->pthread_ret = -1; in line 303.