Add support for cpus_allowed_policy
authorJens Axboe <axboe@fb.com>
Thu, 27 Feb 2014 23:52:02 +0000 (15:52 -0800)
committerJens Axboe <axboe@fb.com>
Thu, 27 Feb 2014 23:52:02 +0000 (15:52 -0800)
Two policies are supported:

shared cpumask is shared between all threads. This is the original
behavior.

split cpumask is split between threads, each thread gets a unique
CPU.

Signed-off-by: Jens Axboe <axboe@fb.com>
13 files changed:
HOWTO
backend.c
cconv.c
fio.1
fio.h
options.c
os/os-freebsd.h
os/os-linux.h
os/os-solaris.h
os/os-windows.h
os/os.h
server.h
thread_options.h

diff --git a/HOWTO b/HOWTO
index 4dacd98965ea1d12ecb86d9d3998e57404edfd28..ef2b631d849e7206323623e91d4e236157c58705 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -928,6 +928,17 @@ cpus_allowed=str Controls the same options as cpumask, but it allows a text
                allows a range of CPUs. Say you wanted a binding to CPUs
                1, 5, and 8-15, you would set cpus_allowed=1,5,8-15.
 
                allows a range of CPUs. Say you wanted a binding to CPUs
                1, 5, and 8-15, you would set cpus_allowed=1,5,8-15.
 
+cpus_allowed_policy=str Set the policy of how fio distributes the CPUs
+               specified by cpus_allowed or cpumask. Two policies are
+               supported:
+
+               shared  All jobs will share the CPU set specified.
+               split   Each job will get a unique CPU from the CPU set.
+
+               'shared' is the default behaviour, if the option isn't
+               specified. If split is specified, then fio will error out if
+               there are more jobs defined than CPUs given in the set.
+
 numa_cpu_nodes=str Set this job running on spcified NUMA nodes' CPUs. The
                arguments allow comma delimited list of cpu numbers,
                A-B ranges, or 'all'. Note, to enable numa options support,
 numa_cpu_nodes=str Set this job running on spcified NUMA nodes' CPUs. The
                arguments allow comma delimited list of cpu numbers,
                A-B ranges, or 'all'. Note, to enable numa options support,
index ee395bd0ea5795ca6a8d9da175b73df574bad412..12c76d8545ef53a02b95223ca8d53237b3175ef4 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -1278,6 +1278,15 @@ static void *thread_main(void *data)
         * allocations.
         */
        if (o->cpumask_set) {
         * allocations.
         */
        if (o->cpumask_set) {
+               if (o->cpus_allowed_policy == FIO_CPUS_SPLIT) {
+                       ret = fio_cpus_split(&o->cpumask, td->thread_number);
+                       if (!ret) {
+                               log_err("fio: no CPUs set\n");
+                               log_err("fio: Try increasing number of available CPUs\n");
+                               td_verror(td, EINVAL, "cpus_split");
+                               goto err;
+                       }
+               }
                ret = fio_setaffinity(td->pid, o->cpumask);
                if (ret == -1) {
                        td_verror(td, errno, "cpu_set_affinity");
                ret = fio_setaffinity(td->pid, o->cpumask);
                if (ret == -1) {
                        td_verror(td, errno, "cpu_set_affinity");
diff --git a/cconv.c b/cconv.c
index fd8d0ad85142568b2d142948ea4b5f638f03b03f..357a7845e559fce6f43a46bb1a411368852d516e 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -188,6 +188,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->numjobs = le32_to_cpu(top->numjobs);
        o->cpumask_set = le32_to_cpu(top->cpumask_set);
        o->verify_cpumask_set = le32_to_cpu(top->verify_cpumask_set);
        o->numjobs = le32_to_cpu(top->numjobs);
        o->cpumask_set = le32_to_cpu(top->cpumask_set);
        o->verify_cpumask_set = le32_to_cpu(top->verify_cpumask_set);
+       o->cpus_allowed_policy = le32_to_cpu(top->cpus_allowed_policy);
        o->iolog = le32_to_cpu(top->iolog);
        o->rwmixcycle = le32_to_cpu(top->rwmixcycle);
        o->nice = le32_to_cpu(top->nice);
        o->iolog = le32_to_cpu(top->iolog);
        o->rwmixcycle = le32_to_cpu(top->rwmixcycle);
        o->nice = le32_to_cpu(top->nice);
@@ -343,6 +344,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->numjobs = cpu_to_le32(o->numjobs);
        top->cpumask_set = cpu_to_le32(o->cpumask_set);
        top->verify_cpumask_set = cpu_to_le32(o->verify_cpumask_set);
        top->numjobs = cpu_to_le32(o->numjobs);
        top->cpumask_set = cpu_to_le32(o->cpumask_set);
        top->verify_cpumask_set = cpu_to_le32(o->verify_cpumask_set);
+       top->cpus_allowed_policy = cpu_to_le32(o->cpus_allowed_policy);
        top->iolog = cpu_to_le32(o->iolog);
        top->rwmixcycle = cpu_to_le32(o->rwmixcycle);
        top->nice = cpu_to_le32(o->nice);
        top->iolog = cpu_to_le32(o->iolog);
        top->rwmixcycle = cpu_to_le32(o->rwmixcycle);
        top->nice = cpu_to_le32(o->nice);
diff --git a/fio.1 b/fio.1
index c530d8440cd04a107a183f634883dc7044199598..863b0e093b38add8f5c86997e62f8b066f07b1bf 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -833,6 +833,25 @@ may run on.  See \fBsched_setaffinity\fR\|(2).
 .BI cpus_allowed \fR=\fPstr
 Same as \fBcpumask\fR, but allows a comma-delimited list of CPU numbers.
 .TP
 .BI cpus_allowed \fR=\fPstr
 Same as \fBcpumask\fR, but allows a comma-delimited list of CPU numbers.
 .TP
+.BI cpus_allowed_policy \fR=\fPstr
+Set the policy of how fio distributes the CPUs specified by \fBcpus_allowed\fR
+or \fBcpumask\fR. Two policies are supported:
+.RS
+.RS
+.TP
+.B shared
+All jobs will share the CPU set specified.
+.TP
+.B split
+Each job will get a unique CPU from the CPU set.
+.RE
+.P
+\fBshared\fR is the default behaviour, if the option isn't specified. If
+\fBsplit\fR is specified, then fio will error out if there are more jobs
+defined than CPUs given in the set.
+.RE
+.P
+.TP
 .BI numa_cpu_nodes \fR=\fPstr
 Set this job running on specified NUMA nodes' CPUs. The arguments allow
 comma delimited list of cpu numbers, A-B ranges, or 'all'.
 .BI numa_cpu_nodes \fR=\fPstr
 Set this job running on specified NUMA nodes' CPUs. The arguments allow
 comma delimited list of cpu numbers, A-B ranges, or 'all'.
diff --git a/fio.h b/fio.h
index 9159b0c2de3e207cd15bf73d683a9accdde72934..6f5f29fb3a979fdceb4649aba90ad15d663c8143 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -629,4 +629,9 @@ enum {
        FIO_RAND_GEN_LFSR,
 };
 
        FIO_RAND_GEN_LFSR,
 };
 
+enum {
+       FIO_CPUS_SHARED         = 0,
+       FIO_CPUS_SPLIT,
+};
+
 #endif
 #endif
index 6d3956e307bf6049abf5dc2ae4b5a56f86e862ef..c1a8f323e956986f30155fa0c43976376c449afc 100644 (file)
--- a/options.c
+++ b/options.c
@@ -394,6 +394,21 @@ static int str_exitall_cb(void)
 }
 
 #ifdef FIO_HAVE_CPU_AFFINITY
 }
 
 #ifdef FIO_HAVE_CPU_AFFINITY
+int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu)
+{
+       const long max_cpu = cpus_online();
+       unsigned int i;
+
+       for (i = 0; i < max_cpu; i++) {
+               if (cpu != i) {
+                       fio_cpu_clear(mask, i);
+                       continue;
+               }
+       }
+
+       return fio_cpu_count(mask);
+}
+
 static int str_cpumask_cb(void *data, unsigned long long *val)
 {
        struct thread_data *td = data;
 static int str_cpumask_cb(void *data, unsigned long long *val)
 {
        struct thread_data *td = data;
@@ -2875,6 +2890,27 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CRED,
        },
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CRED,
        },
+       {
+               .name   = "cpus_allowed_policy",
+               .lname  = "CPUs allowed distribution policy",
+               .type   = FIO_OPT_STR,
+               .off1   = td_var_offset(cpus_allowed_policy),
+               .help   = "Distribution policy for cpus_allowed",
+               .parent = "cpus_allowed",
+               .prio   = 1,
+               .posval = {
+                         { .ival = "shared",
+                           .oval = FIO_CPUS_SHARED,
+                           .help = "Mask shared between threads",
+                         },
+                         { .ival = "split",
+                           .oval = FIO_CPUS_SPLIT,
+                           .help = "Mask split between threads",
+                         },
+               },
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_CRED,
+       },
 #endif
 #ifdef CONFIG_LIBNUMA
        {
 #endif
 #ifdef CONFIG_LIBNUMA
        {
index 57ce409c67fd4d2a5476ab8e3c45577161a8d827..402792a0f7d714f99a41c77ad686d39ef561c548 100644 (file)
@@ -32,6 +32,7 @@ typedef cpuset_t os_cpu_mask_t;
 
 #define fio_cpu_clear(mask, cpu)        (void) CPU_CLR((cpu), (mask))
 #define fio_cpu_set(mask, cpu)          (void) CPU_SET((cpu), (mask))
 
 #define fio_cpu_clear(mask, cpu)        (void) CPU_CLR((cpu), (mask))
 #define fio_cpu_set(mask, cpu)          (void) CPU_SET((cpu), (mask))
+#define fio_cpu_count(maks)            CPU_COUNT((mask))
 
 static inline int fio_cpuset_init(os_cpu_mask_t *mask)
 {
 
 static inline int fio_cpuset_init(os_cpu_mask_t *mask)
 {
index 5d1d62db27a0e2234ceaed73878e6bf4d37316ec..3ed8c2ef31f2bf855709fbf6b655829bc9083bb2 100644 (file)
@@ -61,6 +61,7 @@ typedef struct drand48_data os_random_state_t;
 
 #define fio_cpu_clear(mask, cpu)       (void) CPU_CLR((cpu), (mask))
 #define fio_cpu_set(mask, cpu)         (void) CPU_SET((cpu), (mask))
 
 #define fio_cpu_clear(mask, cpu)       (void) CPU_CLR((cpu), (mask))
 #define fio_cpu_set(mask, cpu)         (void) CPU_SET((cpu), (mask))
+#define fio_cpu_count(maks)            CPU_COUNT((mask))
 
 static inline int fio_cpuset_init(os_cpu_mask_t *mask)
 {
 
 static inline int fio_cpuset_init(os_cpu_mask_t *mask)
 {
index e6612118ace4baf7afcae38eb9a7126ca45af10e..7a0a3f0bfecab77a7e603f690a0350c8facde982 100644 (file)
@@ -111,6 +111,16 @@ static inline int fio_cpuset_init(os_cpu_mask_t *mask)
        return 0;
 }
 
        return 0;
 }
 
+static inline int fio_cpuset_count(os_cpu_mask_t *mask)
+{
+       unsigned int num_cpus;
+
+       if (pset_info(*mask, NULL, &num_cpus, NULL) < 0)
+               return 0;
+
+       return num_cpus;
+}
+
 static inline int fio_cpuset_exit(os_cpu_mask_t *mask)
 {
        if (pset_destroy(*mask) < 0)
 static inline int fio_cpuset_exit(os_cpu_mask_t *mask)
 {
        if (pset_destroy(*mask) < 0)
index de120b64ff7e0b674b53fc878130f63274880dd9..7bfe3d2255e4ea06dc191011c014f36b62435603 100644 (file)
@@ -214,6 +214,11 @@ static inline void fio_cpu_set(os_cpu_mask_t *mask, int cpu)
        *mask |= 1 << cpu;
 }
 
        *mask |= 1 << cpu;
 }
 
+static inline int fio_cpu_count(os_cpu_mask_t *mask, int cpu)
+{
+       return hweight64(*mask);
+}
+
 static inline int fio_cpuset_init(os_cpu_mask_t *mask)
 {
        *mask = 0;
 static inline int fio_cpuset_init(os_cpu_mask_t *mask)
 {
        *mask = 0;
diff --git a/os/os.h b/os/os.h
index 03d1e9a14565f8481dd93db480e1896dfde184ec..a6bc17f09b5797632697de1b4c434f8f1a68482f 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -80,7 +80,10 @@ typedef struct aiocb os_aiocb_t;
 #define fio_getaffinity(pid, mask)     do { } while (0)
 #define fio_cpu_clear(mask, cpu)       do { } while (0)
 #define fio_cpuset_exit(mask)          (-1)
 #define fio_getaffinity(pid, mask)     do { } while (0)
 #define fio_cpu_clear(mask, cpu)       do { } while (0)
 #define fio_cpuset_exit(mask)          (-1)
+#define fio_cpus_split(mask, cpu)      (0)
 typedef unsigned long os_cpu_mask_t;
 typedef unsigned long os_cpu_mask_t;
+#else
+extern int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu);
 #endif
 
 #ifndef FIO_HAVE_IOPRIO
 #endif
 
 #ifndef FIO_HAVE_IOPRIO
index 85d9d7e2e071c325ad41a2d7453956854dac7ab9..8f79c14ae33474cdf39418b147b4991779926cd4 100644 (file)
--- a/server.h
+++ b/server.h
@@ -38,7 +38,7 @@ struct fio_net_cmd_reply {
 };
 
 enum {
 };
 
 enum {
-       FIO_SERVER_VER                  = 31,
+       FIO_SERVER_VER                  = 32,
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
 
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
 
index 14a4e54abcc757a68abe701a60c99a03756459fd..4ea6ebd06a0c07f5212c237f6f7fcfcc808a84c1 100644 (file)
@@ -155,6 +155,7 @@ struct thread_options {
        unsigned int cpumask_set;
        os_cpu_mask_t verify_cpumask;
        unsigned int verify_cpumask_set;
        unsigned int cpumask_set;
        os_cpu_mask_t verify_cpumask;
        unsigned int verify_cpumask_set;
+       unsigned int cpus_allowed_policy;
 #ifdef CONFIG_LIBNUMA
        struct bitmask *numa_cpunodesmask;
        unsigned int numa_cpumask_set;
 #ifdef CONFIG_LIBNUMA
        struct bitmask *numa_cpunodesmask;
        unsigned int numa_cpumask_set;
@@ -378,6 +379,7 @@ struct thread_options_pack {
        uint32_t cpumask_set;
        uint8_t verify_cpumask[FIO_TOP_STR_MAX];
        uint32_t verify_cpumask_set;
        uint32_t cpumask_set;
        uint8_t verify_cpumask[FIO_TOP_STR_MAX];
        uint32_t verify_cpumask_set;
+       uint32_t cpus_allowed_policy;
        uint32_t iolog;
        uint32_t rwmixcycle;
        uint32_t rwmix[DDIR_RWDIR_CNT];
        uint32_t iolog;
        uint32_t rwmixcycle;
        uint32_t rwmix[DDIR_RWDIR_CNT];