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.
+
 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.
 
+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
 ---------------------------
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 \
-       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
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
-.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:
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 "cgroup.h"
 
 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;
@@ -1204,6 +1208,7 @@ err:
        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);
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;
+
+       /*
+        * blkio cgroup support
+        */
+       char *cgroup_root;
+       char *cgroup;
+       unsigned int cgroup_weight;
+       unsigned int cgroup_was_created;
 };
 
 #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",
        },
+       {
+               .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,
        },
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_CGROUPS
 
 #define OS_MAP_ANON            MAP_ANONYMOUS