Skip to content

Commit

Permalink
ioengines: implement dircreate, dirstat, dirdelete engines to fileope…
Browse files Browse the repository at this point in the history
…rations.c

Similar to file operation, directory operation performance is an
important benchmark to file system in practice.

* dircreate engine measures directories create performance
* dirstat engine measures directories lookup performance
* dirdelete engine measures directories delete performance

Signed-off-by: friendy-su <friendy.su@sony.com>
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
  • Loading branch information
friendy-su authored and vincentkfu committed Mar 22, 2024
1 parent 20f42c1 commit a7a817a
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 5 deletions.
15 changes: 15 additions & 0 deletions HOWTO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2192,6 +2192,21 @@ I/O engine
and 'nrfiles', so that the files will be created.
This engine is to measure file delete.

**dircreate**
Simply create the directories and do no I/O to them. You still need to
set `filesize` so that all the accounting still occurs, but no
actual I/O will be done other than creating the directories.

**dirstat**
Simply do stat() and do no I/O to the directories. You need to set 'filesize'
and 'nrfiles', so that directories will be created.
This engine is to measure directory lookup and meta data access.

**dirdelete**
Simply delete the directories by rmdir() and do no I/O to them. You need to set 'filesize'
and 'nrfiles', so that the directories will be created.
This engine is to measure directory delete.

**libpmem**
Read and write using mmap I/O to a file on a filesystem
mounted with DAX on a persistent memory device through the PMDK
Expand Down
121 changes: 116 additions & 5 deletions engines/fileoperations.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* fileoperations engine
* file/directory operations engine
*
* IO engine that doesn't do any IO, just operates files and tracks the latency
* of the file operation.
* IO engine that doesn't do any IO, just operates files/directories
* and tracks the latency of the operation.
*/
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -15,9 +15,15 @@
#include "../optgroup.h"
#include "../oslib/statx.h"

enum fio_engine {
UNKNOWN_OP_ENGINE = 0,
FILE_OP_ENGINE = 1,
DIR_OP_ENGINE = 2,
};

struct fc_data {
enum fio_ddir stat_ddir;
enum fio_engine op_engine;
};

struct filestat_options {
Expand Down Expand Up @@ -61,6 +67,26 @@ static struct fio_option options[] = {
},
};

static int setup_dirs(struct thread_data *td)
{
int ret = 0;
int i;
struct fio_file *f;

for_each_file(td, f, i) {
dprint(FD_FILE, "setup directory %s\n", f->file_name);
ret = fio_mkdir(f->file_name, 0700);
if ((ret && errno != EEXIST)) {
log_err("create directory %s failed with %d\n",
f->file_name, errno);
break;
}
ret = 0;
}
return ret;
}



static int open_file(struct thread_data *td, struct fio_file *f)
{
Expand All @@ -81,7 +107,14 @@ static int open_file(struct thread_data *td, struct fio_file *f)
if (do_lat)
fio_gettime(&start, NULL);

f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
if (((struct fc_data *)td->io_ops_data)->op_engine == FILE_OP_ENGINE)
f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
else if (((struct fc_data *)td->io_ops_data)->op_engine == DIR_OP_ENGINE)
f->fd = fio_mkdir(f->file_name, S_IFDIR);
else {
log_err("fio: unknown file/directory operation engine\n");
return 1;
}

if (f->fd == -1) {
char buf[FIO_VERROR_SIZE];
Expand Down Expand Up @@ -195,7 +228,16 @@ static int delete_file(struct thread_data *td, struct fio_file *f)
if (do_lat)
fio_gettime(&start, NULL);

ret = unlink(f->file_name);
if (((struct fc_data *)td->io_ops_data)->op_engine == FILE_OP_ENGINE)
ret = unlink(f->file_name);
else if (((struct fc_data *)td->io_ops_data)->op_engine == DIR_OP_ENGINE)
ret = rmdir(f->file_name);
else {
log_err("fio: unknown file/directory operation engine\n");
return 1;
}



if (ret == -1) {
char buf[FIO_VERROR_SIZE];
Expand Down Expand Up @@ -250,6 +292,17 @@ static int init(struct thread_data *td)
else if (td_write(td))
data->stat_ddir = DDIR_WRITE;

data->op_engine = UNKNOWN_OP_ENGINE;

if (!strncmp(td->o.ioengine, "file", 4)) {
data->op_engine = FILE_OP_ENGINE;
dprint(FD_FILE, "Operate engine type: file\n");
}
if (!strncmp(td->o.ioengine, "dir", 3)) {
data->op_engine = DIR_OP_ENGINE;
dprint(FD_FILE, "Operate engine type: directory\n");
}

td->io_ops_data = data;
return 0;
}
Expand All @@ -261,6 +314,12 @@ static void cleanup(struct thread_data *td)
free(data);
}

static int remove_dir(struct thread_data *td, struct fio_file *f)
{
dprint(FD_FILE, "remove directory %s\n", f->file_name);
return rmdir(f->file_name);
}

static struct ioengine_ops ioengine_filecreate = {
.name = "filecreate",
.version = FIO_IOOPS_VERSION,
Expand Down Expand Up @@ -302,17 +361,69 @@ static struct ioengine_ops ioengine_filedelete = {
FIO_NOSTATS | FIO_NOFILEHASH,
};

static struct ioengine_ops ioengine_dircreate = {
.name = "dircreate",
.version = FIO_IOOPS_VERSION,
.init = init,
.cleanup = cleanup,
.queue = queue_io,
.get_file_size = get_file_size,
.open_file = open_file,
.close_file = generic_close_file,
.unlink_file = remove_dir,
.flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
FIO_NOSTATS | FIO_NOFILEHASH,
};

static struct ioengine_ops ioengine_dirstat = {
.name = "dirstat",
.version = FIO_IOOPS_VERSION,
.setup = setup_dirs,
.init = init,
.cleanup = cleanup,
.queue = queue_io,
.invalidate = invalidate_do_nothing,
.get_file_size = generic_get_file_size,
.open_file = stat_file,
.unlink_file = remove_dir,
.flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
FIO_NOSTATS | FIO_NOFILEHASH,
.options = options,
.option_struct_size = sizeof(struct filestat_options),
};

static struct ioengine_ops ioengine_dirdelete = {
.name = "dirdelete",
.version = FIO_IOOPS_VERSION,
.setup = setup_dirs,
.init = init,
.invalidate = invalidate_do_nothing,
.cleanup = cleanup,
.queue = queue_io,
.get_file_size = get_file_size,
.open_file = delete_file,
.unlink_file = remove_dir,
.flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
FIO_NOSTATS | FIO_NOFILEHASH,
};


static void fio_init fio_fileoperations_register(void)
{
register_ioengine(&ioengine_filecreate);
register_ioengine(&ioengine_filestat);
register_ioengine(&ioengine_filedelete);
register_ioengine(&ioengine_dircreate);
register_ioengine(&ioengine_dirstat);
register_ioengine(&ioengine_dirdelete);
}

static void fio_exit fio_fileoperations_unregister(void)
{
unregister_ioengine(&ioengine_filecreate);
unregister_ioengine(&ioengine_filestat);
unregister_ioengine(&ioengine_filedelete);
unregister_ioengine(&ioengine_dircreate);
unregister_ioengine(&ioengine_dirstat);
unregister_ioengine(&ioengine_dirdelete);
}
25 changes: 25 additions & 0 deletions examples/dircreate-ioengine.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Example dircreate job
#
# create_on_open is needed so that the open happens during the run and not the
# setup.
#
# openfiles needs to be set so that you do not exceed the maximum allowed open
# files.
#
# filesize needs to be set to a non zero value so fio will actually run, but the
# IO will not really be done and the write latency numbers will only reflect the
# open times.
[global]
create_on_open=1
nrfiles=30
ioengine=dircreate
fallocate=none
filesize=4k
openfiles=1

[t0]
[t1]
[t2]
[t3]
[t4]
[t5]
18 changes: 18 additions & 0 deletions examples/dirdelete-ioengine.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Example dirdelete job

# 'filedelete' engine only do 'rmdir(dirname)'.
# 'filesize' must be set, then directories will be created at setup stage.
# 'unlink' is better set to 0, since the directory is deleted in measurement.
# the options disabled completion latency output such as 'disable_clat' and 'gtod_reduce' must not set.
[global]
ioengine=dirdelete
filesize=4k
nrfiles=200
unlink=0

[t0]
[t1]
[t2]
[t3]
[t4]
[t5]
18 changes: 18 additions & 0 deletions examples/dirstat-ioengine.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Example dirstat job

# 'dirstat' engine only do 'stat(dirname)', file will not be open().
# 'filesize' must be set, then files will be created at setup stage.

[global]
ioengine=dirstat
numjobs=10
filesize=4k
nrfiles=5
thread

[t0]
[t1]
[t2]
[t3]
[t4]
[t5]
15 changes: 15 additions & 0 deletions fio.1
Original file line number Diff line number Diff line change
Expand Up @@ -2004,6 +2004,21 @@ Simply delete files by unlink() and do no I/O to the file. You need to set 'file
and 'nrfiles', so that files will be created.
This engine is to measure file delete.
.TP
.B dircreate
Simply create the directories and do no I/O to them. You still need to set
\fBfilesize\fR so that all the accounting still occurs, but no actual I/O will be
done other than creating the directories.
.TP
.B dirstat
Simply do stat() and do no I/O to the directory. You need to set 'filesize'
and 'nrfiles', so that directories will be created.
This engine is to measure directory lookup and meta data access.
.TP
.B dirdelete
Simply delete directories by unlink() and do no I/O to the directory. You need to set 'filesize'
and 'nrfiles', so that directories will be created.
This engine is to measure directory delete.
.TP
.B libpmem
Read and write using mmap I/O to a file on a filesystem
mounted with DAX on a persistent memory device through the PMDK
Expand Down

0 comments on commit a7a817a

Please sign in to comment.