From: Dave Chinner <david@fromorbit.com>
To: xfs@oss.sgi.com
Cc: rwheeler@redhat.com
Subject: [PATCH] [RFC] fs_mark: add asynchronous fsync
Date: Thu, 12 Jun 2014 18:56:45 +1000 [thread overview]
Message-ID: <20140612085645.GP9508@dastard> (raw)
In-Reply-To: <1402562047-31276-1-git-send-email-david@fromorbit.com>
From: Dave Chinner <dchinner@redhat.com>
to be able to test the performance impact of asynchronous bulk
fsync of newly created files, add an option to fsmark to be able
to use libaio for dispatch and collection of fsync operations. This
requires a filesystem that has wired up IO_CMD_FSYNC in the kernel.
This is all a bit hacky, but it does wait for all fsyncs to
complete. aio contexts have to be set up after the runner thread
have been forked, so it's not really using a global iocb and event
array as the code appears - there's one per child process doing
work, and hence there's no need for locking or other fancy stuff.
No attempt has been made to tune the number of AIOs allowed to be in
flight, nor has there been any attempt to optimise the collection of
completion events nor return errors if an fsync fails. It works well
enough for testing the new XFS code and that's all I need from it.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
--- a/fs_mark.c 2011-07-30 10:09:43.000000000 +1000
+++ b/fs_mark.c 2014-06-12 18:01:43.000000000 +1000
@@ -41,6 +41,7 @@
#include <dirent.h>
#include <ctype.h>
#include <time.h>
+#include <libaio.h>
#include <linux/types.h>
#include <linux/limits.h>
@@ -68,6 +69,7 @@
"\t-S Sync Method (0:No Sync, 1:fsyncBeforeClose, "
"2:sync/1_fsync, 3:PostReverseFsync, "
"4:syncPostReverseFsync, 5:PostFsync, 6:syncPostFsync)\n",
+ "\t-A <use aio_fsync>\n"
"\t[-D number (of subdirectories)]\n",
"\t[-N number (of files in each subdirectory in Round Robin mode)]\n",
"\t[-d dir1 ... -d dirN]\n", "\t[-l log_file_name]\n",
@@ -84,18 +86,101 @@
}
/*
+ * aio for fsync
+ */
+#define MAX_AIO_EVENTS 1024
+io_context_t ctxp;
+struct iocb *iocbs[MAX_AIO_EVENTS];
+struct io_event ioevents[MAX_AIO_EVENTS];
+int aio_next;
+int aio_flight;
+
+void
+init_aio_fsync(void)
+{
+ int i, r;
+
+ memset(&ctxp, 0, sizeof(ctxp));
+ r = io_setup(MAX_AIO_EVENTS, &ctxp);
+ if (r) {
+ printf("FAIL! io_setup returned %d\n", r);
+ cleanup_exit();
+ }
+ for (i = 0; i < MAX_AIO_EVENTS; ++i) {
+ iocbs[i] = calloc(1, sizeof(struct iocb));
+ if (iocbs[i] == NULL) {
+ printf("failed to allocate an iocb\n");
+ cleanup_exit();
+ }
+ }
+
+}
+
+void
+get_fsync_completions(int threshold)
+{
+ int i, r;
+
+ if (!(sync_method & FSYNC_ASYNC))
+ return;
+
+ while (aio_flight > threshold) {
+ /* gather up some completions */
+ r = io_getevents(ctxp, 1, MAX_AIO_EVENTS, ioevents, NULL);
+ if (r < 0) {
+ printf("FAIL! io_getevents returned %d\n", r);
+ cleanup_exit();
+ }
+
+ aio_flight -= r;
+ for (i = 0; i < r; ++i) {
+ if (ioevents[i].res)
+ printf("FAIL! aio_fsync returned %d\n",
+ ioevents[i].res);
+ }
+ usleep(1000);
+ }
+}
+
+int
+do_fsync(int fd)
+{
+ int r, i;
+
+ if (!(sync_method & FSYNC_ASYNC))
+ return fsync(fd);
+
+
+ get_fsync_completions(MAX_AIO_EVENTS / 2);
+
+ /* submit the fsync */
+ i = aio_next++ % MAX_AIO_EVENTS;
+ aio_flight++;
+ r = io_fsync(ctxp, iocbs[i], NULL, fd);
+ if (r != 1) {
+ printf("FAIL! io_submit returned %d\n", r);
+ cleanup_exit();
+ }
+
+}
+
+/*
* Run through the specified arguments and make sure that they make sense.
*/
void process_args(int argc, char **argv, char **envp)
{
int ret;
+ int fsync_async = 0;
/*
* Parse all of the options that the user specified.
*/
while ((ret =
- getopt(argc, argv, "vhkFr:S:N:D:d:l:L:n:p:s:t:w:")) != EOF) {
+ getopt(argc, argv, "AvhkFr:S:N:D:d:l:L:n:p:s:t:w:")) != EOF) {
switch (ret) {
+ case 'A':
+ fsync_async++;
+ break;
case 'v': /* verbose stats */
verbose_stats = 1;
break;
@@ -250,6 +335,8 @@
" for -N num_per_subdir to make sense\n");
usage();
}
+ if (fsync_async)
+ sync_method |= FSYNC_ASYNC;
/*
* We need at least one thread per specified directory.
@@ -650,6 +737,8 @@
close_usec = max_close_usec = min_close_usec = 0ULL;
unlink_usec = max_unlink_usec = min_unlink_usec = 0ULL;
+ init_aio_fsync();
+
/*
* MAIN FILE WRITE LOOP:
* This loop measures the specific steps in creating files:
@@ -714,7 +803,7 @@
if (sync_method & FSYNC_BEFORE_CLOSE) {
start(0);
- if (fsync(fd) == -1) {
+ if (do_fsync(fd) == -1) {
fprintf(stderr, "fs_mark: fsync failed %s\n",
strerror(errno));
cleanup_exit();
@@ -775,7 +864,7 @@
cleanup_exit();
}
- if (fsync(fd) == -1) {
+ if (do_fsync(fd) == -1) {
fprintf(stderr, "fs_mark: fsync failed %s\n",
strerror(errno));
cleanup_exit();
@@ -813,7 +902,7 @@
cleanup_exit();
}
- if (fsync(fd) == -1) {
+ if (do_fsync(fd) == -1) {
fprintf(stderr, "fs_mark: fsync failed %s\n",
strerror(errno));
cleanup_exit();
@@ -849,7 +938,7 @@
cleanup_exit();
}
- if (fsync(fd) == -1) {
+ if (do_fsync(fd) == -1) {
fprintf(stderr, "fs_mark: fsync failed %s\n",
strerror(errno));
cleanup_exit();
@@ -859,6 +948,8 @@
fsync_usec += stop(0, 0);
}
+ get_fsync_completions(0);
+
/*
* Record the total time spent in the file writing loop - we ignore the time spent unlinking files
*/
@@ -1209,6 +1300,8 @@
fs_mark_version, num_threads, ctime(&time_run));
fprintf(log_fp, "#\tSync method: %s\n",
sync_policy_string[sync_method_type]);
+ if (sync_method & FSYNC_ASYNC)
+ fprintf(log_fp, "#\tUsing aio_fsync\n");
if (num_subdirs > 1) {
fprintf(log_fp,
"#\tDirectories: %s across %d subdirectories with %d %s.\n",
--- a/fs_mark.h 2011-07-30 10:09:43.000000000 +1000
+++ b/fs_mark.h 2014-06-12 18:01:43.000000000 +1000
@@ -70,6 +70,7 @@
#define FSYNC_FIRST_FILE (0x4)
#define FSYNC_POST_REVERSE (0x8)
#define FSYNC_POST_IN_ORDER (0x10)
+#define FSYNC_ASYNC (0x20)
#define SYNC_TEST_NONE (0) /* -S 0 */
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next prev parent reply other threads:[~2014-06-12 8:56 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-12 8:34 [PATCH] [RFC] xfs: wire up aio_fsync method Dave Chinner
2014-06-12 8:56 ` Dave Chinner [this message]
2014-06-12 14:13 ` Christoph Hellwig
2014-06-12 23:44 ` Dave Chinner
2014-06-13 16:23 ` Christoph Hellwig
2014-06-15 22:33 ` Dave Chinner
2014-06-16 2:00 ` Dave Chinner
2014-06-16 2:58 ` Jens Axboe
2014-06-16 7:19 ` Dave Chinner
2014-06-16 19:30 ` Jens Axboe
2014-06-16 22:27 ` Dave Chinner
2014-06-17 13:23 ` Jens Axboe
2014-06-18 0:28 ` Dave Chinner
2014-06-18 2:24 ` Jens Axboe
2014-06-18 3:13 ` Dave Chinner
2014-06-18 3:20 ` Jens Axboe
2014-06-18 5:02 ` Dave Chinner
2014-06-18 6:13 ` Dave Chinner
2014-06-16 21:06 ` Michael Kerrisk (man-pages)
2014-06-17 14:01 ` Christoph Hellwig
2014-06-12 15:24 ` Brian Foster
2014-06-12 23:57 ` Dave Chinner
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=20140612085645.GP9508@dastard \
--to=david@fromorbit.com \
--cc=rwheeler@redhat.com \
--cc=xfs@oss.sgi.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