Add support for blkio cgroups on Linux
authorJens Axboe <jens.axboe@oracle.com>
Fri, 4 Dec 2009 09:05:02 +0000 (10:05 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Fri, 4 Dec 2009 09:05:02 +0000 (10:05 +0100)
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
HOWTO
Makefile
cgroup.c [new file with mode: 0644]
cgroup.h [new file with mode: 0644]
fio.1
fio.c
fio.h
options.c
os/os-linux.h

diff --git a/HOWTO b/HOWTO
index 9b3a6848e11c1a43867cd5da6a666ecff12df444..7a7d14ea0816080d794d25f4d899603e2eee57a8 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -994,6 +994,7 @@ gtod_cpu=int        Sometimes it's cheaper to dedicate a single thread of
                for doing these time calls will be excluded from other
                uses. Fio will manually clear it from the CPU mask of other
                jobs.
                for doing these time calls will be excluded from other
                uses. Fio will manually clear it from the CPU mask of other
                jobs.
+
 continue_on_error=bool Normally fio will exit the job on the first observed
                failure. If this option is set, fio will continue the job when
                there is a 'non-fatal error' (EIO or EILSEQ) until the runtime
 continue_on_error=bool Normally fio will exit the job on the first observed
                failure. If this option is set, fio will continue the job when
                there is a 'non-fatal error' (EIO or EILSEQ) until the runtime
@@ -1003,6 +1004,21 @@ continue_on_error=bool   Normally fio will exit the job on the first observed
                given in the stats is the first error that was hit during the
                run.
 
                given in the stats is the first error that was hit during the
                run.
 
+cgroup_root=str        Root of the mounted blkio cgroup file systems. This is a Linux
+               specific IO controller. If your system doesn't have it mounted,
+               you can do so with:
+
+               # mount -t cgroup -o blkio none /cgroup
+
+               The cgroup_root defaults to /cgroup, if mounted elsewhere
+               please specify this option.
+
+cgroup=str     Add job to this control group. If it doesn't exist, it will
+               be created.
+
+cgroup_weight=int      Set the weight of the cgroup to this value. See
+               the documentation that comes with the kernel, allowed values
+               are in the range of 100..1000.
 
 6.0 Interpreting the output
 ---------------------------
 
 6.0 Interpreting the output
 ---------------------------
index 4f95a5da3f274493ef74b5a913fc645a39aa6e11..ce63cfc896d5e4dab3e027d8058879fb16d06a2a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,8 @@ PROGS   = fio
 SCRIPTS = fio_generate_plots
 OBJS = gettime.o fio.o ioengines.o init.o stat.o log.o time.o filesetup.o \
        eta.o verify.o memory.o io_u.o parse.o mutex.o options.o \
 SCRIPTS = fio_generate_plots
 OBJS = gettime.o fio.o ioengines.o init.o stat.o log.o time.o filesetup.o \
        eta.o verify.o memory.o io_u.o parse.o mutex.o options.o \
-       rbtree.o diskutil.o fifo.o blktrace.o smalloc.o filehash.o helpers.o
+       rbtree.o diskutil.o fifo.o blktrace.o smalloc.o filehash.o helpers.o \
+       cgroup.o
 
 OBJS += crc/crc7.o
 OBJS += crc/crc16.o
 
 OBJS += crc/crc7.o
 OBJS += crc/crc16.o
diff --git a/cgroup.c b/cgroup.c
new file mode 100644 (file)
index 0000000..15641e6
--- /dev/null
+++ b/cgroup.c
@@ -0,0 +1,115 @@
+/*
+ * Code related to setting up a blkio cgroup
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "fio.h"
+#include "cgroup.h"
+
+static char *get_cgroup_root(struct thread_data *td)
+{
+       char *str = malloc(64);
+
+       if (td->o.cgroup)
+               sprintf(str, "%s/%s", td->o.cgroup_root, td->o.cgroup);
+       else
+               sprintf(str, "%s/%s", td->o.cgroup_root, td->o.name);
+
+       return str;
+}
+
+/*
+ * Add pid to given class
+ */
+static int cgroup_add_pid(struct thread_data *td)
+{
+       char *root, tmp[256];
+       FILE *f;
+
+       root = get_cgroup_root(td);
+       sprintf(tmp, "%s/tasks", root);
+
+       f = fopen(tmp, "w");
+       if (!f) {
+               td_verror(td, errno, "cgroup open tasks");
+               return 1;
+       }
+
+       fprintf(f, "%d", td->pid);
+       fclose(f);
+       free(root);
+       return 0;
+}
+
+/*
+ * Move pid to root class
+ */
+static int cgroup_del_pid(struct thread_data *td)
+{
+       char tmp[256];
+       FILE *f;
+
+       sprintf(tmp, "%s/tasks", td->o.cgroup_root);
+       f = fopen(tmp, "w");
+       if (!f) {
+               td_verror(td, errno, "cgroup open tasks");
+               return 1;
+       }
+
+       fprintf(f, "%d", td->pid);
+       fclose(f);
+       return 0;
+}
+
+
+int cgroup_setup(struct thread_data *td)
+{
+       char *root, tmp[256];
+       FILE *f;
+
+       /*
+        * Create container, if it doesn't exist
+        */
+       root = get_cgroup_root(td);
+       if (mkdir(root, 0755) < 0) {
+               int __e = errno;
+
+               if (__e != EEXIST) {
+                       td_verror(td, __e, "cgroup mkdir");
+                       return 1;
+               }
+       } else
+               td->o.cgroup_was_created = 1;
+
+       sprintf(tmp, "%s/blkio.weight", root);
+       f = fopen(tmp, "w");
+       if (!f) {
+               td_verror(td, errno, "cgroup open weight");
+               return 1;
+       }
+
+       fprintf(f, "%d", td->o.cgroup_weight);
+       fclose(f);
+       free(root);
+
+       if (cgroup_add_pid(td))
+               return 1;
+
+       return 0;
+}
+
+void cgroup_shutdown(struct thread_data *td)
+{
+       if (!td->o.cgroup_weight)
+               return;
+
+       cgroup_del_pid(td);
+
+       if (td->o.cgroup_was_created) {
+               char *root;
+
+               root = get_cgroup_root(td);
+               rmdir(root);
+               free(root);
+       }
+}
diff --git a/cgroup.h b/cgroup.h
new file mode 100644 (file)
index 0000000..65fa3ad
--- /dev/null
+++ b/cgroup.h
@@ -0,0 +1,22 @@
+#ifndef FIO_CGROUP_H
+#define FIO_CGROUP_H
+
+#ifdef FIO_HAVE_CGROUPS
+
+int cgroup_setup(struct thread_data *td);
+void cgroup_shutdown(struct thread_data *td);
+
+#else
+
+static inline int cgroup_setup(struct thread_data *td)
+{
+       td_verror(td, EINVAL, "cgroup_setup");
+       return 1;
+}
+
+static inline void cgroup_shutdown(struct thread_data *td)
+{
+}
+
+#endif
+#endif
diff --git a/fio.1 b/fio.1
index 4445d0a3a99989191c70e8359e8c8bc82248613e..648b4e9c6d73fb3c040aed3167e8d925a98e1e17 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -725,13 +725,22 @@ entering the kernel with a gettimeofday() call. The CPU set aside for doing
 these time calls will be excluded from other uses. Fio will manually clear it
 from the CPU mask of other jobs.
 .TP
 these time calls will be excluded from other uses. Fio will manually clear it
 from the CPU mask of other jobs.
 .TP
-.BI continue_on_error \fR=\fPbool
-Normally fio will exit the job on the first observed failure. If this option is
-set, fio will continue the job when there is a 'non-fatal error'
-(\fBEIO\fR or \fBEILSEQ\fR) until the runtime is exceeded or the I/O size
-specified is completed. If this option is used, there are two more stats that
-are appended, the total error count and the first error. The error field given
-in the stats is the first error that was hit during the run.
+.BI cgroup_root \fR=\fPstr
+Root of the mounted blkio cgroup file systems. This is a Linux
+specific IO controller. If your system doesn't have it mounted,
+you can do so with:
+
+# mount -t cgroup -o blkio none /cgroup
+
+The cgroup_root defaults to /cgroup, if mounted elsewhere please specify this
+option.
+.TP
+.BI cgroup \fR=\fPstr
+Add job to this control group. If it doesn't exist, it will be created.
+.TP
+.BI cgroup_weight \fR=\fPint
+Set the weight of the cgroup to this value. See the documentation that comes
+with the kernel, allowed values are in the range of 100..1000.
 .SH OUTPUT
 While running, \fBfio\fR will display the status of the created jobs.  For
 example:
 .SH OUTPUT
 While running, \fBfio\fR will display the status of the created jobs.  For
 example:
diff --git a/fio.c b/fio.c
index 434b50372832c49952fd2195c4e4377ae3088227..4bbab5af9a12e9c0d00fa559bdddb94107b42f77 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -39,6 +39,7 @@
 #include "smalloc.h"
 #include "verify.h"
 #include "diskutil.h"
 #include "smalloc.h"
 #include "verify.h"
 #include "diskutil.h"
+#include "cgroup.h"
 
 unsigned long page_mask;
 unsigned long page_size;
 
 unsigned long page_mask;
 unsigned long page_size;
@@ -1075,6 +1076,9 @@ static void *thread_main(void *data)
                }
        }
 
                }
        }
 
+       if (td->o.cgroup_weight && cgroup_setup(td))
+               goto err;
+
        if (nice(td->o.nice) == -1) {
                td_verror(td, errno, "nice");
                goto err;
        if (nice(td->o.nice) == -1) {
                td_verror(td, errno, "nice");
                goto err;
@@ -1204,6 +1208,7 @@ err:
        close_and_free_files(td);
        close_ioengine(td);
        cleanup_io_u(td);
        close_and_free_files(td);
        close_ioengine(td);
        cleanup_io_u(td);
+       cgroup_shutdown(td);
 
        if (td->o.cpumask_set) {
                int ret = fio_cpuset_exit(&td->o.cpumask);
 
        if (td->o.cpumask_set) {
                int ret = fio_cpuset_exit(&td->o.cpumask);
diff --git a/fio.h b/fio.h
index 214fbd268ca92e9081748be70b5c9cb07e3bff0f..aa5124cd03a805d9158391131d3e1788c1f4b9e9 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -271,6 +271,14 @@ struct thread_options {
         * Benchmark profile type
         */
        unsigned int profile;
         * Benchmark profile type
         */
        unsigned int profile;
+
+       /*
+        * blkio cgroup support
+        */
+       char *cgroup_root;
+       char *cgroup;
+       unsigned int cgroup_weight;
+       unsigned int cgroup_was_created;
 };
 
 #define FIO_VERROR_SIZE        128
 };
 
 #define FIO_VERROR_SIZE        128
index ff277657ea0264f2394984578ab52a629170c940..cb6337c27207664b80ac7acd81156ade8687519b 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1726,6 +1726,28 @@ static struct fio_option options[] = {
                },
                .help   = "Select a specific builtin performance test",
        },
                },
                .help   = "Select a specific builtin performance test",
        },
+       {
+               .name   = "cgroup_root",
+               .type   = FIO_OPT_STR_STORE,
+               .off1   = td_var_offset(cgroup_root),
+               .help   = "Root of mounted blkio cgroup",
+               .def    = "/cgroup",
+       },
+       {
+               .name   = "cgroup",
+               .type   = FIO_OPT_STR_STORE,
+               .off1   = td_var_offset(cgroup),
+               .help   = "Add job to cgroup of this name",
+       },
+       {
+               .name   = "cgroup_weight",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(cgroup_weight),
+               .help   = "Use given weight for cgroup",
+               .minval = 100,
+               .maxval = 1000,
+               .def    = "0",
+       },
        {
                .name = NULL,
        },
        {
                .name = NULL,
        },
index e4c4c3fd2f094eceaad485f1d53b2d35def66367..ac42264b1a7b6db77b9ef78d7d104382c522b656 100644 (file)
@@ -31,6 +31,7 @@
 #define FIO_HAVE_POSIXAIO_FSYNC
 #define FIO_HAVE_PSHARED_MUTEX
 #define FIO_HAVE_CL_SIZE
 #define FIO_HAVE_POSIXAIO_FSYNC
 #define FIO_HAVE_PSHARED_MUTEX
 #define FIO_HAVE_CL_SIZE
+#define FIO_HAVE_CGROUPS
 
 #define OS_MAP_ANON            MAP_ANONYMOUS
 
 
 #define OS_MAP_ANON            MAP_ANONYMOUS