All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/11] Improve io_uring and libaio IO priority support
@ 2021-09-03 15:20 Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 01/11] manpage: fix formatting Niklas Cassel
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Niklas Cassel <niklas.cassel@wdc.com>

This series improves io_uring/libaio engine support for IO priority,
adding options to allow for mixed priority workloads to be specified
more easily and to match the kernel supported IO priority features.

This series is based on Damien's V1 series which can be found here:
https://www.spinics.net/lists/fio/msg09614.html

Major changes since v1:

- Rename new options:
aioprio -> cmdprio
aioprioclass -> cmdprio_class
aioprio_bssplit -> cmdprio_bssplit.
Since these options are all related to cmdprio_percentage, it makes sense
to keep the cmdprio prefix for these new options.
Renaming also makes it more clear that these are not libaio specifc options.

- Added io_uring support for these new options.
All these new options works for ioengine=libaio and ioengine=io_uring

- Added a new helper file: engines/cmdprio.h and moved as much common code
that I could share between io_uring and libaio in there.

Kept Damien's authorship as I feel that I haven't changed the original code
sufficiently to warrant an authorship change.


Comments are welcome!

Kind regards,
Niklas

Damien Le Moal (11):
  manpage: fix formatting
  manpage: fix definition of prio and prioclass options
  tools: fiograph: do not overwrite input script file
  os: introduce ioprio_value() helper
  options: make parsing functions available to ioengines
  libaio,io_uring: improve cmdprio_percentage option
  libaio,io_uring: introduce cmdprio_class and cmdprio options
  libaio,io_uring: introduce cmdprio_bssplit
  libaio,io_uring: relax cmdprio_percentage constraints
  fio: Introduce the log_prio option
  examples: add examples for cmdprio_* IO priority options

 HOWTO                           |  59 ++++++++++---
 backend.c                       |   1 +
 cconv.c                         |   2 +
 client.c                        |   2 +
 engines/cmdprio.h               | 144 ++++++++++++++++++++++++++++++
 engines/filecreate.c            |   2 +-
 engines/filedelete.c            |   2 +-
 engines/filestat.c              |   2 +-
 engines/io_uring.c              | 152 +++++++++++++++++++++++++-------
 engines/libaio.c                | 125 ++++++++++++++++++++++----
 eta.c                           |   2 +-
 examples/cmdprio-bssplit.fio    |  17 ++++
 examples/cmdprio-bssplit.png    | Bin 0 -> 45606 bytes
 examples/cmdprio-percentage.fio |  17 ++++
 examples/cmdprio-percentage.png | Bin 0 -> 46271 bytes
 fio.1                           |  73 +++++++++++----
 fio.h                           |   5 ++
 init.c                          |   4 +
 io_u.c                          |  14 ++-
 io_u.h                          |  10 ++-
 iolog.c                         |  45 +++++++---
 iolog.h                         |  16 +++-
 options.c                       |  50 ++++++-----
 os/os-android.h                 |  20 +++--
 os/os-dragonfly.h               |   1 +
 os/os-linux.h                   |  20 +++--
 os/os.h                         |   4 +
 server.h                        |   3 +-
 stat.c                          |  75 ++++++++--------
 stat.h                          |   9 +-
 thread_options.h                |  19 ++++
 tools/fiograph/fiograph.conf    |   4 +-
 tools/fiograph/fiograph.py      |   4 +-
 33 files changed, 724 insertions(+), 179 deletions(-)
 create mode 100644 engines/cmdprio.h
 create mode 100644 examples/cmdprio-bssplit.fio
 create mode 100644 examples/cmdprio-bssplit.png
 create mode 100644 examples/cmdprio-percentage.fio
 create mode 100644 examples/cmdprio-percentage.png

-- 
2.31.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 01/11] manpage: fix formatting
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 02/11] manpage: fix definition of prio and prioclass options Niklas Cassel
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

For ioengine options supported by multiple ioengines, remove spaces
after commas in the ioengine list to have troff correctly format in bold
the entire ioengine list and option name. Also add "=int" indicators
missing for some options.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 fio.1 | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/fio.1 b/fio.1
index 382cebfc..25d9f545 100644
--- a/fio.1
+++ b/fio.1
@@ -1962,7 +1962,7 @@ In addition, there are some parameters which are only valid when a specific
 with the caveat that when used on the command line, they must come after the
 \fBioengine\fR that defines them is selected.
 .TP
-.BI (io_uring, libaio)cmdprio_percentage \fR=\fPint
+.BI (io_uring,libaio)cmdprio_percentage \fR=\fPint
 Set the percentage of I/O that will be issued with higher priority by setting
 the priority bit. Non-read I/O is likely unaffected by ``cmdprio_percentage``.
 This option cannot be used with the `prio` or `prioclass` options. For this
@@ -2043,20 +2043,20 @@ Detect when I/O threads are done, then exit.
 .BI (libhdfs)namenode \fR=\fPstr
 The hostname or IP address of a HDFS cluster namenode to contact.
 .TP
-.BI (libhdfs)port
+.BI (libhdfs)port \fR=\fPint
 The listening port of the HFDS cluster namenode.
 .TP
-.BI (netsplice,net)port
+.BI (netsplice,net)port \fR=\fPint
 The TCP or UDP port to bind to or connect to. If this is used with
 \fBnumjobs\fR to spawn multiple instances of the same job type, then
 this will be the starting port number since fio will use a range of
 ports.
 .TP
-.BI (rdma, librpma_*)port
+.BI (rdma,librpma_*)port \fR=\fPint
 The port to use for RDMA-CM communication. This should be the same
 value on the client and the server side.
 .TP
-.BI (netsplice,net, rdma)hostname \fR=\fPstr
+.BI (netsplice,net,rdma)hostname \fR=\fPstr
 The hostname or IP address to use for TCP, UDP or RDMA-CM based I/O.
 If the job is a TCP listener or UDP reader, the hostname is not used
 and must be omitted unless it is a valid UDP multicast address.
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 02/11] manpage: fix definition of prio and prioclass options
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 01/11] manpage: fix formatting Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 03/11] tools: fiograph: do not overwrite input script file Niklas Cassel
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

Remove the reference to the hipri_percentage option in the definition of
the prio and prioclass options as hipri_percentage controls the use of
RWF_HIPRI flag which triggers I/O completion polling, which is unrelated
with I/O priority (polling and I/O priority can be used together). This
change is done in both fio man page and HOWTO document.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 HOWTO | 6 ++----
 fio.1 | 6 ++----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/HOWTO b/HOWTO
index a2cf20f6..96b680dd 100644
--- a/HOWTO
+++ b/HOWTO
@@ -2974,14 +2974,12 @@ Threads, processes and job synchronization
 	between 0 and 7, with 0 being the highest.  See man
 	:manpage:`ionice(1)`. Refer to an appropriate manpage for other operating
 	systems since meaning of priority may differ. For per-command priority
-	setting, see I/O engine specific `cmdprio_percentage` and `hipri_percentage`
-	options.
+	setting, see I/O engine specific `cmdprio_percentage` option.
 
 .. option:: prioclass=int
 
 	Set the I/O priority class. See man :manpage:`ionice(1)`. For per-command
-	priority setting, see I/O engine specific `cmdprio_percentage` and
-	`hipri_percentage` options.
+	priority setting, see I/O engine specific `cmdprio_percentage` option.
 
 .. option:: cpus_allowed=str
 
diff --git a/fio.1 b/fio.1
index 25d9f545..87ca8e73 100644
--- a/fio.1
+++ b/fio.1
@@ -2693,13 +2693,11 @@ Set the I/O priority value of this job. Linux limits us to a positive value
 between 0 and 7, with 0 being the highest. See man
 \fBionice\fR\|(1). Refer to an appropriate manpage for other operating
 systems since meaning of priority may differ. For per-command priority
-setting, see I/O engine specific `cmdprio_percentage` and `hipri_percentage`
-options.
+setting, see the I/O engine specific `cmdprio_percentage` option.
 .TP
 .BI prioclass \fR=\fPint
 Set the I/O priority class. See man \fBionice\fR\|(1). For per-command
-priority setting, see I/O engine specific `cmdprio_percentage` and `hipri_percent`
-options.
+priority setting, see the I/O engine specific `cmdprio_percentage` option.
 .TP
 .BI cpus_allowed \fR=\fPstr
 Controls the same options as \fBcpumask\fR, but accepts a textual
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 03/11] tools: fiograph: do not overwrite input script file
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 01/11] manpage: fix formatting Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 02/11] manpage: fix definition of prio and prioclass options Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 04/11] os: introduce ioprio_value() helper Niklas Cassel
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

In fiograph.py, the setup_commandline() function mistakenly initializes
the output_file variable to the input fio script file, causing this file
to always be overwritten, even if an output file is specified using the
--output option. Fix this by properly initializing the output_file
variable using the --output option argument value. If an output file
name is not provided, the input script file name is used by default.

Also fix fiograph configuration file to remove the cmdprio_percentage
option repeated entry for io_uring and libaio.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 tools/fiograph/fiograph.conf | 4 ++--
 tools/fiograph/fiograph.py   | 4 +++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/fiograph/fiograph.conf b/tools/fiograph/fiograph.conf
index 5becc4d9..1957e11d 100644
--- a/tools/fiograph/fiograph.conf
+++ b/tools/fiograph/fiograph.conf
@@ -51,10 +51,10 @@ specific_options=https  http_host  http_user  http_pass  http_s3_key  http_s3_ke
 specific_options=ime_psync  ime_psyncv
 
 [ioengine_io_uring]
-specific_options=hipri  cmdprio_percentage  cmdprio_percentage  fixedbufs  registerfiles  sqthread_poll  sqthread_poll_cpu  nonvectored  uncached  nowait  force_async
+specific_options=hipri  cmdprio_percentage  fixedbufs  registerfiles  sqthread_poll  sqthread_poll_cpu  nonvectored  uncached  nowait  force_async
 
 [ioengine_libaio]
-specific_options=userspace_reap  cmdprio_percentage  cmdprio_percentage  nowait
+specific_options=userspace_reap  cmdprio_percentage  nowait
 
 [ioengine_libcufile]
 specific_options=gpu_dev_ids  cuda_io
diff --git a/tools/fiograph/fiograph.py b/tools/fiograph/fiograph.py
index 7695c964..b5669a2d 100755
--- a/tools/fiograph/fiograph.py
+++ b/tools/fiograph/fiograph.py
@@ -292,9 +292,11 @@ def setup_commandline():
 def main():
     global config_file
     args = setup_commandline()
-    output_file = args.file
     if args.output is None:
+        output_file = args.file
         output_file = output_file.replace('.fio', '')
+    else:
+        output_file = args.output
     config_file = configparser.RawConfigParser(allow_no_value=True)
     config_file.read(args.config)
     fio_to_graphviz(args.file, args.format).render(output_file, view=args.view)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 04/11] os: introduce ioprio_value() helper
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (2 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 03/11] tools: fiograph: do not overwrite input script file Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 05/11] options: make parsing functions available to ioengines Niklas Cassel
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

Introduce the ioprio_value() helper function to calculate a priority
value based on a priority class and priority level. For Linux and
Android, this is defined as an integer equal to the priority class
shifted left by 13 bits and or-ed with the priority level. For
Dragonfly, ioprio_value() simply returns the priority level as there
is no concept of priority class.

Use this new helper in the io_uring and libaio engines to set IO
priority when the cmdprio_percentage option is used.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 engines/io_uring.c |  2 +-
 engines/libaio.c   |  2 +-
 os/os-android.h    | 15 ++++++++++-----
 os/os-dragonfly.h  |  1 +
 os/os-linux.h      | 15 ++++++++++-----
 os/os.h            |  1 +
 6 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/engines/io_uring.c b/engines/io_uring.c
index b8d4cf91..4f8b5582 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -382,7 +382,7 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 	struct ioring_options *o = td->eo;
 	struct ioring_data *ld = td->io_ops_data;
 	if (rand_between(&td->prio_state, 0, 99) < o->cmdprio_percentage) {
-		ld->sqes[io_u->index].ioprio = IOPRIO_CLASS_RT << IOPRIO_CLASS_SHIFT;
+		ld->sqes[io_u->index].ioprio = ioprio_value(IOPRIO_CLASS_RT, 0);
 		io_u->flags |= IO_U_F_PRIORITY;
 	} else {
 		ld->sqes[io_u->index].ioprio = 0;
diff --git a/engines/libaio.c b/engines/libaio.c
index b909b79e..b12b6ffc 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -136,7 +136,7 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 {
 	struct libaio_options *o = td->eo;
 	if (rand_between(&td->prio_state, 0, 99) < o->cmdprio_percentage) {
-		io_u->iocb.aio_reqprio = IOPRIO_CLASS_RT << IOPRIO_CLASS_SHIFT;
+		io_u->iocb.aio_reqprio = ioprio_value(IOPRIO_CLASS_RT, 0);
 		io_u->iocb.u.c.flags |= IOCB_FLAG_IOPRIO;
 		io_u->flags |= IO_U_F_PRIORITY;
 	}
diff --git a/os/os-android.h b/os/os-android.h
index a81cd815..f013172f 100644
--- a/os/os-android.h
+++ b/os/os-android.h
@@ -173,16 +173,21 @@ enum {
 #define IOPRIO_MIN_PRIO_CLASS	0
 #define IOPRIO_MAX_PRIO_CLASS	3
 
-static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
+static inline int ioprio_value(int ioprio_class, int ioprio)
 {
 	/*
 	 * If no class is set, assume BE
 	 */
-	if (!ioprio_class)
-		ioprio_class = IOPRIO_CLASS_BE;
+        if (!ioprio_class)
+                ioprio_class = IOPRIO_CLASS_BE;
+
+	return (ioprio_class << IOPRIO_CLASS_SHIFT) | ioprio;
+}
 
-	ioprio |= ioprio_class << IOPRIO_CLASS_SHIFT;
-	return syscall(__NR_ioprio_set, which, who, ioprio);
+static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
+{
+	return syscall(__NR_ioprio_set, which, who,
+		       ioprio_value(ioprio_class, ioprio));
 }
 
 #ifndef BLKGETSIZE64
diff --git a/os/os-dragonfly.h b/os/os-dragonfly.h
index 6e465894..5b37a37e 100644
--- a/os/os-dragonfly.h
+++ b/os/os-dragonfly.h
@@ -171,6 +171,7 @@ static inline int fio_getaffinity(int pid, os_cpu_mask_t *mask)
  * ioprio_set() with 4 arguments, so define fio's ioprio_set() as a macro.
  * Note that there is no idea of class within ioprio_set(2) unlike Linux.
  */
+#define ioprio_value(ioprio_class, ioprio)	(ioprio)
 #define ioprio_set(which, who, ioprio_class, ioprio)	\
 	ioprio_set(which, who, ioprio)
 
diff --git a/os/os-linux.h b/os/os-linux.h
index 16ed5258..12886037 100644
--- a/os/os-linux.h
+++ b/os/os-linux.h
@@ -118,16 +118,21 @@ enum {
 #define IOPRIO_MIN_PRIO_CLASS	0
 #define IOPRIO_MAX_PRIO_CLASS	3
 
-static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
+static inline int ioprio_value(int ioprio_class, int ioprio)
 {
 	/*
 	 * If no class is set, assume BE
 	 */
-	if (!ioprio_class)
-		ioprio_class = IOPRIO_CLASS_BE;
+        if (!ioprio_class)
+                ioprio_class = IOPRIO_CLASS_BE;
+
+	return (ioprio_class << IOPRIO_CLASS_SHIFT) | ioprio;
+}
 
-	ioprio |= ioprio_class << IOPRIO_CLASS_SHIFT;
-	return syscall(__NR_ioprio_set, which, who, ioprio);
+static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
+{
+	return syscall(__NR_ioprio_set, which, who,
+		       ioprio_value(ioprio_class, ioprio));
 }
 
 #ifndef CONFIG_HAVE_GETTID
diff --git a/os/os.h b/os/os.h
index 17daf91d..f2257a7c 100644
--- a/os/os.h
+++ b/os/os.h
@@ -118,6 +118,7 @@ extern int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu);
 #endif
 
 #ifndef FIO_HAVE_IOPRIO
+#define ioprio_value(prioclass, prio)	(0)
 #define ioprio_set(which, who, prioclass, prio)	(0)
 #endif
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 05/11] options: make parsing functions available to ioengines
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (3 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 04/11] os: introduce ioprio_value() helper Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 07/11] libaio,io_uring: introduce cmdprio_class and cmdprio options Niklas Cassel
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

Move the declaration of split_parse_ddir(), str_split_parse() and
the split_parse_fn typedef to thread_options.h so that IO engines
can use these functions to parse options. The definition of struct
split is also moved to thread_options.h from options.c.

The type of the split_parse_fn callback function is changed to add a
void * argument that can be used for an option parsing callback to pass
a private data pointer to the split_parse_fn function. This can be used
by an IO engine to pass a pointer to its engine specific option
structure as td->eo is not yet set when options are being parsed.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 options.c        | 40 ++++++++++++++++------------------------
 thread_options.h | 15 +++++++++++++++
 2 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/options.c b/options.c
index 8c2ab7cc..708f3703 100644
--- a/options.c
+++ b/options.c
@@ -73,13 +73,7 @@ static int bs_cmp(const void *p1, const void *p2)
 	return (int) bsp1->perc - (int) bsp2->perc;
 }
 
-struct split {
-	unsigned int nr;
-	unsigned long long val1[ZONESPLIT_MAX];
-	unsigned long long val2[ZONESPLIT_MAX];
-};
-
-static int split_parse_ddir(struct thread_options *o, struct split *split,
+int split_parse_ddir(struct thread_options *o, struct split *split,
 			    char *str, bool absolute, unsigned int max_splits)
 {
 	unsigned long long perc;
@@ -138,8 +132,8 @@ static int split_parse_ddir(struct thread_options *o, struct split *split,
 	return 0;
 }
 
-static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str,
-			bool data)
+static int bssplit_ddir(struct thread_options *o, void *eo,
+			enum fio_ddir ddir, char *str, bool data)
 {
 	unsigned int i, perc, perc_missing;
 	unsigned long long max_bs, min_bs;
@@ -211,10 +205,8 @@ static int bssplit_ddir(struct thread_options *o, enum fio_ddir ddir, char *str,
 	return 0;
 }
 
-typedef int (split_parse_fn)(struct thread_options *, enum fio_ddir, char *, bool);
-
-static int str_split_parse(struct thread_data *td, char *str,
-			   split_parse_fn *fn, bool data)
+int str_split_parse(struct thread_data *td, char *str,
+		    split_parse_fn *fn, void *eo, bool data)
 {
 	char *odir, *ddir;
 	int ret = 0;
@@ -223,37 +215,37 @@ static int str_split_parse(struct thread_data *td, char *str,
 	if (odir) {
 		ddir = strchr(odir + 1, ',');
 		if (ddir) {
-			ret = fn(&td->o, DDIR_TRIM, ddir + 1, data);
+			ret = fn(&td->o, eo, DDIR_TRIM, ddir + 1, data);
 			if (!ret)
 				*ddir = '\0';
 		} else {
 			char *op;
 
 			op = strdup(odir + 1);
-			ret = fn(&td->o, DDIR_TRIM, op, data);
+			ret = fn(&td->o, eo, DDIR_TRIM, op, data);
 
 			free(op);
 		}
 		if (!ret)
-			ret = fn(&td->o, DDIR_WRITE, odir + 1, data);
+			ret = fn(&td->o, eo, DDIR_WRITE, odir + 1, data);
 		if (!ret) {
 			*odir = '\0';
-			ret = fn(&td->o, DDIR_READ, str, data);
+			ret = fn(&td->o, eo, DDIR_READ, str, data);
 		}
 	} else {
 		char *op;
 
 		op = strdup(str);
-		ret = fn(&td->o, DDIR_WRITE, op, data);
+		ret = fn(&td->o, eo, DDIR_WRITE, op, data);
 		free(op);
 
 		if (!ret) {
 			op = strdup(str);
-			ret = fn(&td->o, DDIR_TRIM, op, data);
+			ret = fn(&td->o, eo, DDIR_TRIM, op, data);
 			free(op);
 		}
 		if (!ret)
-			ret = fn(&td->o, DDIR_READ, str, data);
+			ret = fn(&td->o, eo, DDIR_READ, str, data);
 	}
 
 	return ret;
@@ -270,7 +262,7 @@ static int str_bssplit_cb(void *data, const char *input)
 	strip_blank_front(&str);
 	strip_blank_end(str);
 
-	ret = str_split_parse(td, str, bssplit_ddir, false);
+	ret = str_split_parse(td, str, bssplit_ddir, NULL, false);
 
 	if (parse_dryrun()) {
 		int i;
@@ -906,8 +898,8 @@ static int str_sfr_cb(void *data, const char *str)
 }
 #endif
 
-static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir,
-			   char *str, bool absolute)
+static int zone_split_ddir(struct thread_options *o, void *eo,
+			   enum fio_ddir ddir, char *str, bool absolute)
 {
 	unsigned int i, perc, perc_missing, sperc, sperc_missing;
 	struct split split;
@@ -1012,7 +1004,7 @@ static int parse_zoned_distribution(struct thread_data *td, const char *input,
 	}
 	str += strlen(pre);
 
-	ret = str_split_parse(td, str, zone_split_ddir, absolute);
+	ret = str_split_parse(td, str, zone_split_ddir, NULL, absolute);
 
 	free(p);
 
diff --git a/thread_options.h b/thread_options.h
index 4b4ecfe1..7133faf6 100644
--- a/thread_options.h
+++ b/thread_options.h
@@ -44,6 +44,12 @@ enum dedupe_mode {
 #define BSSPLIT_MAX	64
 #define ZONESPLIT_MAX	256
 
+struct split {
+	unsigned int nr;
+	unsigned long long val1[ZONESPLIT_MAX];
+	unsigned long long val2[ZONESPLIT_MAX];
+};
+
 struct bssplit {
 	uint64_t bs;
 	uint32_t perc;
@@ -678,4 +684,13 @@ extern void convert_thread_options_to_net(struct thread_options_pack *top, struc
 extern int fio_test_cconv(struct thread_options *);
 extern void options_default_fill(struct thread_options *o);
 
+typedef int (split_parse_fn)(struct thread_options *, void *,
+			     enum fio_ddir, char *, bool);
+
+extern int str_split_parse(struct thread_data *td, char *str,
+			   split_parse_fn *fn, void *eo, bool data);
+
+extern int split_parse_ddir(struct thread_options *o, struct split *split,
+			    char *str, bool absolute, unsigned int max_splits);
+
 #endif
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 07/11] libaio,io_uring: introduce cmdprio_class and cmdprio options
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (4 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 05/11] options: make parsing functions available to ioengines Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 06/11] libaio,io_uring: improve cmdprio_percentage option Niklas Cassel
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

When the cmdprio_percentage option is used, the specified percentage of
IO will be issued with the highest priority class IOPRIO_CLASS_RT. This
priority class maps to the ATA NCQ "high" priority level and allows
exercising a SATA device to measure its command latency characteristics
in the presence of low and high priority commands.

Beside ATA NCQ commands, Linux block IO schedulers also support IO
priorities and will behave differently in the presence of IOs with
different IO priority classes and values. However, cmdprio_percentage
does not allow specifying all possible priority classes and values.

To solve this, introduce libaio and io_uring engine specific options
cmdprio_class and cmdprio. These new options are the equivalent
of the prioclass and prio options and allow specifying the priority
class and priority value to use for asynchronous I/Os when the
cmdprio_percentage option is used. If not specified, the I/O priority
class defaults to IOPRIO_CLASS_RT and the I/O priority value to 0,
as before. Similarly to the cmdprio_percentage option, these options
can specify different values for read and write I/Os using a comma
separated list.

The manpage, HOWTO and fiograph configuration file are updated to
document these new options.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 HOWTO                        | 26 +++++++++++++++++--
 engines/cmdprio.h            | 11 ++++++++-
 engines/io_uring.c           | 48 ++++++++++++++++++++++++++++++++++--
 engines/libaio.c             | 48 ++++++++++++++++++++++++++++++++++--
 fio.1                        | 24 ++++++++++++++++--
 tools/fiograph/fiograph.conf |  4 +--
 6 files changed, 150 insertions(+), 11 deletions(-)

diff --git a/HOWTO b/HOWTO
index 916f5191..8b7d4957 100644
--- a/HOWTO
+++ b/HOWTO
@@ -2172,6 +2172,26 @@ with the caveat that when used on the command line, they must come after the
     to be effective, NCQ priority must be supported and enabled, and `direct=1'
     option must be used. fio must also be run as the root user.
 
+.. option:: cmdprio_class=int[,int] : [io_uring] [libaio]
+
+	Set the I/O priority class to use for I/Os that must be issued with
+	a priority when :option:`cmdprio_percentage` is set. If not specified
+	when :option:`cmdprio_percentage` is set, this defaults to the highest
+	priority class. A single value applies to reads and writes.
+	Comma-separated values may be specified for reads and writes. See
+	:manpage:`ionice(1)`. See also the :option:`prioclass` option.
+
+.. option:: cmdprio=int[,int] : [io_uring] [libaio]
+
+	Set the I/O priority value to use for I/Os that must be issued with
+	a priority when :option:`cmdprio_percentage` is set. If not specified
+	when :option:`cmdprio_percentage` is set, this defaults to 0.
+	Linux limits us to a positive value between 0 and 7, with 0 being the
+	highest. A single value applies to reads and writes. Comma-separated
+	values may be specified for reads and writes. See :manpage:`ionice(1)`.
+	Refer to an appropriate manpage for other operating systems since
+	meaning of priority may differ. See also the :option:`prio` option.
+
 .. option:: fixedbufs : [io_uring]
 
     If fio is asked to do direct IO, then Linux will map pages for each
@@ -2974,12 +2994,14 @@ Threads, processes and job synchronization
 	between 0 and 7, with 0 being the highest.  See man
 	:manpage:`ionice(1)`. Refer to an appropriate manpage for other operating
 	systems since meaning of priority may differ. For per-command priority
-	setting, see I/O engine specific `cmdprio_percentage` option.
+	setting, see I/O engine specific :option:`cmdprio_percentage` and
+	:option:`cmdprio` options.
 
 .. option:: prioclass=int
 
 	Set the I/O priority class. See man :manpage:`ionice(1)`. For per-command
-	priority setting, see I/O engine specific `cmdprio_percentage` option.
+	priority setting, see I/O engine specific :option:`cmdprio_percentage`
+	and :option:`cmdprio_class` options.
 
 .. option:: cpus_allowed=str
 
diff --git a/engines/cmdprio.h b/engines/cmdprio.h
index 19120d78..e3b42182 100644
--- a/engines/cmdprio.h
+++ b/engines/cmdprio.h
@@ -10,6 +10,8 @@
 
 struct cmdprio {
 	unsigned int percentage[DDIR_RWDIR_CNT];
+	unsigned int class[DDIR_RWDIR_CNT];
+	unsigned int level[DDIR_RWDIR_CNT];
 };
 
 static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
@@ -19,9 +21,16 @@ static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
 	bool has_cmdprio_percentage = false;
 	int i;
 
+	/*
+	 * If cmdprio_percentage is set and cmdprio_class is not set,
+	 * default to RT priority class.
+	 */
 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
-		if (cmdprio->percentage[i])
+		if (cmdprio->percentage[i]) {
+			if (!cmdprio->class[i])
+				cmdprio->class[i] = IOPRIO_CLASS_RT;
 			has_cmdprio_percentage = true;
+		}
 	}
 
 	/*
diff --git a/engines/io_uring.c b/engines/io_uring.c
index 1731eb24..1591ee4e 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -133,6 +133,36 @@ static struct fio_option options[] = {
 		.category = FIO_OPT_C_ENGINE,
 		.group	= FIO_OPT_G_IOURING,
 	},
+	{
+		.name	= "cmdprio_class",
+		.lname	= "Asynchronous I/O priority class",
+		.type	= FIO_OPT_INT,
+		.off1	= offsetof(struct ioring_options,
+				   cmdprio.class[DDIR_READ]),
+		.off2	= offsetof(struct ioring_options,
+				   cmdprio.class[DDIR_WRITE]),
+		.help	= "Set asynchronous IO priority class",
+		.minval	= IOPRIO_MIN_PRIO_CLASS + 1,
+		.maxval	= IOPRIO_MAX_PRIO_CLASS,
+		.interval = 1,
+		.category = FIO_OPT_C_ENGINE,
+		.group	= FIO_OPT_G_IOURING,
+	},
+	{
+		.name	= "cmdprio",
+		.lname	= "Asynchronous I/O priority level",
+		.type	= FIO_OPT_INT,
+		.off1	= offsetof(struct ioring_options,
+				   cmdprio.level[DDIR_READ]),
+		.off2	= offsetof(struct ioring_options,
+				   cmdprio.level[DDIR_WRITE]),
+		.help	= "Set asynchronous IO priority level",
+		.minval	= IOPRIO_MIN_PRIO,
+		.maxval	= IOPRIO_MAX_PRIO,
+		.interval = 1,
+		.category = FIO_OPT_C_ENGINE,
+		.group	= FIO_OPT_G_IOURING,
+	},
 #else
 	{
 		.name	= "cmdprio_percentage",
@@ -140,6 +170,18 @@ static struct fio_option options[] = {
 		.type	= FIO_OPT_UNSUPPORTED,
 		.help	= "Your platform does not support I/O priority classes",
 	},
+	{
+		.name	= "cmdprio_class",
+		.lname	= "Asynchronous I/O priority class",
+		.type	= FIO_OPT_UNSUPPORTED,
+		.help	= "Your platform does not support I/O priority classes",
+	},
+	{
+		.name	= "cmdprio",
+		.lname	= "Asynchronous I/O priority level",
+		.type	= FIO_OPT_UNSUPPORTED,
+		.help	= "Your platform does not support I/O priority classes",
+	},
 #endif
 	{
 		.name	= "fixedbufs",
@@ -389,10 +431,12 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 	struct ioring_data *ld = td->io_ops_data;
 	struct io_uring_sqe *sqe = &ld->sqes[io_u->index];
 	struct cmdprio *cmdprio = &o->cmdprio;
-	unsigned int p = cmdprio->percentage[io_u->ddir];
+	enum fio_ddir ddir = io_u->ddir;
+	unsigned int p = cmdprio->percentage[ddir];
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
-		sqe->ioprio = ioprio_value(IOPRIO_CLASS_RT, 0);
+		sqe->ioprio =
+			ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
 		io_u->flags |= IO_U_F_PRIORITY;
 	} else {
 		sqe->ioprio = 0;
diff --git a/engines/libaio.c b/engines/libaio.c
index 8cf560c5..8b965fe2 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -87,6 +87,36 @@ static struct fio_option options[] = {
 		.category = FIO_OPT_C_ENGINE,
 		.group	= FIO_OPT_G_LIBAIO,
 	},
+	{
+		.name	= "cmdprio_class",
+		.lname	= "Asynchronous I/O priority class",
+		.type	= FIO_OPT_INT,
+		.off1	= offsetof(struct libaio_options,
+				   cmdprio.class[DDIR_READ]),
+		.off2	= offsetof(struct libaio_options,
+				   cmdprio.class[DDIR_WRITE]),
+		.help	= "Set asynchronous IO priority class",
+		.minval	= IOPRIO_MIN_PRIO_CLASS + 1,
+		.maxval	= IOPRIO_MAX_PRIO_CLASS,
+		.interval = 1,
+		.category = FIO_OPT_C_ENGINE,
+		.group	= FIO_OPT_G_LIBAIO,
+	},
+	{
+		.name	= "cmdprio",
+		.lname	= "Asynchronous I/O priority level",
+		.type	= FIO_OPT_INT,
+		.off1	= offsetof(struct libaio_options,
+				   cmdprio.level[DDIR_READ]),
+		.off2	= offsetof(struct libaio_options,
+				   cmdprio.level[DDIR_WRITE]),
+		.help	= "Set asynchronous IO priority level",
+		.minval	= IOPRIO_MIN_PRIO,
+		.maxval	= IOPRIO_MAX_PRIO,
+		.interval = 1,
+		.category = FIO_OPT_C_ENGINE,
+		.group	= FIO_OPT_G_LIBAIO,
+	},
 #else
 	{
 		.name	= "cmdprio_percentage",
@@ -94,6 +124,18 @@ static struct fio_option options[] = {
 		.type	= FIO_OPT_UNSUPPORTED,
 		.help	= "Your platform does not support I/O priority classes",
 	},
+	{
+		.name	= "cmdprio_class",
+		.lname	= "Asynchronous I/O priority class",
+		.type	= FIO_OPT_UNSUPPORTED,
+		.help	= "Your platform does not support I/O priority classes",
+	},
+	{
+		.name	= "cmdprio",
+		.lname	= "Asynchronous I/O priority level",
+		.type	= FIO_OPT_UNSUPPORTED,
+		.help	= "Your platform does not support I/O priority classes",
+	},
 #endif
 	{
 		.name	= "nowait",
@@ -142,10 +184,12 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 {
 	struct libaio_options *o = td->eo;
 	struct cmdprio *cmdprio = &o->cmdprio;
-	unsigned int p = cmdprio->percentage[io_u->ddir];
+	enum fio_ddir ddir = io_u->ddir;
+	unsigned int p = cmdprio->percentage[ddir];
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
-		io_u->iocb.aio_reqprio = ioprio_value(IOPRIO_CLASS_RT, 0);
+		io_u->iocb.aio_reqprio =
+			ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
 		io_u->iocb.u.c.flags |= IOCB_FLAG_IOPRIO;
 		io_u->flags |= IO_U_F_PRIORITY;
 	}
diff --git a/fio.1 b/fio.1
index 3611da98..09b97de3 100644
--- a/fio.1
+++ b/fio.1
@@ -1970,6 +1970,24 @@ with the `prio` or `prioclass` options. For this option to be effective,
 NCQ priority must be supported and enabled, and `direct=1' option must be
 used. fio must also be run as the root user.
 .TP
+.BI (io_uring,libaio)cmdprio_class \fR=\fPint[,int]
+Set the I/O priority class to use for I/Os that must be issued with a
+priority when \fBcmdprio_percentage\fR is set. If not specified when
+\fBcmdprio_percentage\fR is set, this defaults to the highest priority
+class. A single value applies to reads and writes. Comma-separated
+values may be specified for reads and writes. See man \fBionice\fR\|(1).
+See also the \fBprioclass\fR option.
+.TP
+.BI (io_uring,libaio)cmdprio \fR=\fPint[,int]
+Set the I/O priority value to use for I/Os that must be issued with a
+priority when \fBcmdprio_percentage\fR is set. If not specified when
+\fBcmdprio_percentage\fR is set, this defaults to 0. Linux limits us to
+a positive value between 0 and 7, with 0 being the highest. A single
+value applies to reads and writes. Comma-separated values may be specified
+for reads and writes. See man \fBionice\fR\|(1). Refer to an appropriate
+manpage for other operating systems since the meaning of priority may differ.
+See also the \fBprio\fR option.
+.TP
 .BI (io_uring)fixedbufs
 If fio is asked to do direct IO, then Linux will map pages for each IO call, and
 release them when IO is done. If this option is set, the pages are pre-mapped
@@ -2693,11 +2711,13 @@ Set the I/O priority value of this job. Linux limits us to a positive value
 between 0 and 7, with 0 being the highest. See man
 \fBionice\fR\|(1). Refer to an appropriate manpage for other operating
 systems since meaning of priority may differ. For per-command priority
-setting, see the I/O engine specific `cmdprio_percentage` option.
+setting, see the I/O engine specific `cmdprio_percentage` and
+`cmdprio` options.
 .TP
 .BI prioclass \fR=\fPint
 Set the I/O priority class. See man \fBionice\fR\|(1). For per-command
-priority setting, see the I/O engine specific `cmdprio_percentage` option.
+priority setting, see the I/O engine specific `cmdprio_percentage` and
+`cmdprio_class` options.
 .TP
 .BI cpus_allowed \fR=\fPstr
 Controls the same options as \fBcpumask\fR, but accepts a textual
diff --git a/tools/fiograph/fiograph.conf b/tools/fiograph/fiograph.conf
index 1957e11d..5ba59c52 100644
--- a/tools/fiograph/fiograph.conf
+++ b/tools/fiograph/fiograph.conf
@@ -51,10 +51,10 @@ specific_options=https  http_host  http_user  http_pass  http_s3_key  http_s3_ke
 specific_options=ime_psync  ime_psyncv
 
 [ioengine_io_uring]
-specific_options=hipri  cmdprio_percentage  fixedbufs  registerfiles  sqthread_poll  sqthread_poll_cpu  nonvectored  uncached  nowait  force_async
+specific_options=hipri  cmdprio_percentage  cmdprio_class  cmdprio  fixedbufs  registerfiles  sqthread_poll  sqthread_poll_cpu  nonvectored  uncached  nowait  force_async
 
 [ioengine_libaio]
-specific_options=userspace_reap  cmdprio_percentage  nowait
+specific_options=userspace_reap  cmdprio_percentage  cmdprio_class  cmdprio  nowait
 
 [ioengine_libcufile]
 specific_options=gpu_dev_ids  cuda_io
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 06/11] libaio,io_uring: improve cmdprio_percentage option
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (5 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 07/11] libaio,io_uring: introduce cmdprio_class and cmdprio options Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 08/11] libaio,io_uring: introduce cmdprio_bssplit Niklas Cassel
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

The cmdprio_percentage option of the libaio and io_uring engines defines
a single percentage that applies to all IO operations, regardless of
their direction. This prevents defining different high priority IO
percentages for reads and writes operations. This differentiation can
however be useful in the case of a mixed read-write workload (rwmixread
and rwmixwrite options).

Change the option definition to allow specifying a comma separated list
of percentages, 2 at most, one for reads and one for writes. If only a
single percentage is defined, it applies to both reads and writes as
before. The cmdprio_percentage option becomes an array of DDIR_RWDIR_CNT
elements indexed with enum fio_ddir values. The last entry of the array
(for DDIR_TRIM) is always 0.

Also create a new cmdprio helper file, engines/cmdprio.h,
such that we can avoid code duplication between io_uring and libaio
io engines. This helper file will be extended in subsequent patches.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 HOWTO              | 16 ++++++++--------
 engines/cmdprio.h  | 44 ++++++++++++++++++++++++++++++++++++++++++++
 engines/io_uring.c | 40 ++++++++++++++++++++++------------------
 engines/libaio.c   | 35 ++++++++++++++++++++---------------
 fio.1              | 14 +++++++-------
 5 files changed, 101 insertions(+), 48 deletions(-)
 create mode 100644 engines/cmdprio.h

diff --git a/HOWTO b/HOWTO
index 96b680dd..916f5191 100644
--- a/HOWTO
+++ b/HOWTO
@@ -2163,14 +2163,14 @@ In addition, there are some parameters which are only valid when a specific
 with the caveat that when used on the command line, they must come after the
 :option:`ioengine` that defines them is selected.
 
-.. option:: cmdprio_percentage=int : [io_uring] [libaio]
-
-    Set the percentage of I/O that will be issued with higher priority by setting
-    the priority bit. Non-read I/O is likely unaffected by ``cmdprio_percentage``.
-    This option cannot be used with the `prio` or `prioclass` options. For this
-    option to set the priority bit properly, NCQ priority must be supported and
-    enabled and :option:`direct`\=1 option must be used. fio must also be run as
-    the root user.
+.. option:: cmdprio_percentage=int[,int] : [io_uring] [libaio]
+
+    Set the percentage of I/O that will be issued with the highest priority.
+    Default: 0. A single value applies to reads and writes. Comma-separated
+    values may be specified for reads and writes. This option cannot be used
+    with the :option:`prio` or :option:`prioclass` options. For this option
+    to be effective, NCQ priority must be supported and enabled, and `direct=1'
+    option must be used. fio must also be run as the root user.
 
 .. option:: fixedbufs : [io_uring]
 
diff --git a/engines/cmdprio.h b/engines/cmdprio.h
new file mode 100644
index 00000000..19120d78
--- /dev/null
+++ b/engines/cmdprio.h
@@ -0,0 +1,44 @@
+/*
+ * IO priority handling declarations and helper functions common to the
+ * libaio and io_uring engines.
+ */
+
+#ifndef FIO_CMDPRIO_H
+#define FIO_CMDPRIO_H
+
+#include "../fio.h"
+
+struct cmdprio {
+	unsigned int percentage[DDIR_RWDIR_CNT];
+};
+
+static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
+			    bool *has_cmdprio)
+{
+	struct thread_options *to = &td->o;
+	bool has_cmdprio_percentage = false;
+	int i;
+
+	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+		if (cmdprio->percentage[i])
+			has_cmdprio_percentage = true;
+	}
+
+	/*
+	 * Check for option conflicts
+	 */
+	if (has_cmdprio_percentage &&
+	    (fio_option_is_set(to, ioprio) ||
+	     fio_option_is_set(to, ioprio_class))) {
+		log_err("%s: cmdprio_percentage option and mutually exclusive "
+			"prio or prioclass option is set, exiting\n",
+			to->name);
+		return 1;
+	}
+
+	*has_cmdprio = has_cmdprio_percentage;
+
+	return 0;
+}
+
+#endif
diff --git a/engines/io_uring.c b/engines/io_uring.c
index 4f8b5582..1731eb24 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -23,6 +23,7 @@
 
 #include "../lib/types.h"
 #include "../os/linux/io_uring.h"
+#include "cmdprio.h"
 
 struct io_sq_ring {
 	unsigned *head;
@@ -69,12 +70,14 @@ struct ioring_data {
 	int prepped;
 
 	struct ioring_mmap mmap[3];
+
+	bool use_cmdprio;
 };
 
 struct ioring_options {
 	void *pad;
 	unsigned int hipri;
-	unsigned int cmdprio_percentage;
+	struct cmdprio cmdprio;
 	unsigned int fixedbufs;
 	unsigned int registerfiles;
 	unsigned int sqpoll_thread;
@@ -120,8 +123,11 @@ static struct fio_option options[] = {
 		.name	= "cmdprio_percentage",
 		.lname	= "high priority percentage",
 		.type	= FIO_OPT_INT,
-		.off1	= offsetof(struct ioring_options, cmdprio_percentage),
-		.minval	= 1,
+		.off1	= offsetof(struct ioring_options,
+				   cmdprio.percentage[DDIR_READ]),
+		.off2	= offsetof(struct ioring_options,
+				   cmdprio.percentage[DDIR_WRITE]),
+		.minval	= 0,
 		.maxval	= 100,
 		.help	= "Send high priority I/O this percentage of the time",
 		.category = FIO_OPT_C_ENGINE,
@@ -381,13 +387,16 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 {
 	struct ioring_options *o = td->eo;
 	struct ioring_data *ld = td->io_ops_data;
-	if (rand_between(&td->prio_state, 0, 99) < o->cmdprio_percentage) {
-		ld->sqes[io_u->index].ioprio = ioprio_value(IOPRIO_CLASS_RT, 0);
+	struct io_uring_sqe *sqe = &ld->sqes[io_u->index];
+	struct cmdprio *cmdprio = &o->cmdprio;
+	unsigned int p = cmdprio->percentage[io_u->ddir];
+
+	if (p && rand_between(&td->prio_state, 0, 99) < p) {
+		sqe->ioprio = ioprio_value(IOPRIO_CLASS_RT, 0);
 		io_u->flags |= IO_U_F_PRIORITY;
 	} else {
-		ld->sqes[io_u->index].ioprio = 0;
+		sqe->ioprio = 0;
 	}
-	return;
 }
 
 static enum fio_q_status fio_ioring_queue(struct thread_data *td,
@@ -395,7 +404,6 @@ static enum fio_q_status fio_ioring_queue(struct thread_data *td,
 {
 	struct ioring_data *ld = td->io_ops_data;
 	struct io_sq_ring *ring = &ld->sq_ring;
-	struct ioring_options *o = td->eo;
 	unsigned tail, next_tail;
 
 	fio_ro_check(td, io_u);
@@ -418,7 +426,7 @@ static enum fio_q_status fio_ioring_queue(struct thread_data *td,
 	if (next_tail == atomic_load_acquire(ring->head))
 		return FIO_Q_BUSY;
 
-	if (o->cmdprio_percentage)
+	if (ld->use_cmdprio)
 		fio_ioring_prio_prep(td, io_u);
 	ring->array[tail & ld->sq_ring_mask] = io_u->index;
 	atomic_store_release(ring->tail, next_tail);
@@ -729,7 +737,8 @@ static int fio_ioring_init(struct thread_data *td)
 {
 	struct ioring_options *o = td->eo;
 	struct ioring_data *ld;
-	struct thread_options *to = &td->o;
+	struct cmdprio *cmdprio = &o->cmdprio;
+	int ret;
 
 	/* sqthread submission requires registered files */
 	if (o->sqpoll_thread)
@@ -753,14 +762,9 @@ static int fio_ioring_init(struct thread_data *td)
 
 	td->io_ops_data = ld;
 
-	/*
-	 * Check for option conflicts
-	 */
-	if ((fio_option_is_set(to, ioprio) || fio_option_is_set(to, ioprio_class)) &&
-			o->cmdprio_percentage != 0) {
-		log_err("%s: cmdprio_percentage option and mutually exclusive "
-				"prio or prioclass option is set, exiting\n", to->name);
-		td_verror(td, EINVAL, "fio_io_uring_init");
+	ret = fio_cmdprio_init(td, cmdprio, &ld->use_cmdprio);
+	if (ret) {
+		td_verror(td, EINVAL, "fio_ioring_init");
 		return 1;
 	}
 
diff --git a/engines/libaio.c b/engines/libaio.c
index b12b6ffc..8cf560c5 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -15,6 +15,7 @@
 #include "../lib/pow2.h"
 #include "../optgroup.h"
 #include "../lib/memalign.h"
+#include "cmdprio.h"
 
 /* Should be defined in newest aio_abi.h */
 #ifndef IOCB_FLAG_IOPRIO
@@ -50,12 +51,14 @@ struct libaio_data {
 	unsigned int queued;
 	unsigned int head;
 	unsigned int tail;
+
+	bool use_cmdprio;
 };
 
 struct libaio_options {
 	void *pad;
 	unsigned int userspace_reap;
-	unsigned int cmdprio_percentage;
+	struct cmdprio cmdprio;
 	unsigned int nowait;
 };
 
@@ -74,8 +77,11 @@ static struct fio_option options[] = {
 		.name	= "cmdprio_percentage",
 		.lname	= "high priority percentage",
 		.type	= FIO_OPT_INT,
-		.off1	= offsetof(struct libaio_options, cmdprio_percentage),
-		.minval	= 1,
+		.off1	= offsetof(struct libaio_options,
+				   cmdprio.percentage[DDIR_READ]),
+		.off2	= offsetof(struct libaio_options,
+				   cmdprio.percentage[DDIR_WRITE]),
+		.minval	= 0,
 		.maxval	= 100,
 		.help	= "Send high priority I/O this percentage of the time",
 		.category = FIO_OPT_C_ENGINE,
@@ -135,12 +141,14 @@ static int fio_libaio_prep(struct thread_data *td, struct io_u *io_u)
 static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 {
 	struct libaio_options *o = td->eo;
-	if (rand_between(&td->prio_state, 0, 99) < o->cmdprio_percentage) {
+	struct cmdprio *cmdprio = &o->cmdprio;
+	unsigned int p = cmdprio->percentage[io_u->ddir];
+
+	if (p && rand_between(&td->prio_state, 0, 99) < p) {
 		io_u->iocb.aio_reqprio = ioprio_value(IOPRIO_CLASS_RT, 0);
 		io_u->iocb.u.c.flags |= IOCB_FLAG_IOPRIO;
 		io_u->flags |= IO_U_F_PRIORITY;
 	}
-	return;
 }
 
 static struct io_u *fio_libaio_event(struct thread_data *td, int event)
@@ -246,7 +254,6 @@ static enum fio_q_status fio_libaio_queue(struct thread_data *td,
 					  struct io_u *io_u)
 {
 	struct libaio_data *ld = td->io_ops_data;
-	struct libaio_options *o = td->eo;
 
 	fio_ro_check(td, io_u);
 
@@ -277,7 +284,7 @@ static enum fio_q_status fio_libaio_queue(struct thread_data *td,
 		return FIO_Q_COMPLETED;
 	}
 
-	if (o->cmdprio_percentage)
+	if (ld->use_cmdprio)
 		fio_libaio_prio_prep(td, io_u);
 
 	ld->iocbs[ld->head] = &io_u->iocb;
@@ -420,8 +427,9 @@ static int fio_libaio_post_init(struct thread_data *td)
 static int fio_libaio_init(struct thread_data *td)
 {
 	struct libaio_data *ld;
-	struct thread_options *to = &td->o;
 	struct libaio_options *o = td->eo;
+	struct cmdprio *cmdprio = &o->cmdprio;
+	int ret;
 
 	ld = calloc(1, sizeof(*ld));
 
@@ -432,16 +440,13 @@ static int fio_libaio_init(struct thread_data *td)
 	ld->io_us = calloc(ld->entries, sizeof(struct io_u *));
 
 	td->io_ops_data = ld;
-	/*
-	 * Check for option conflicts
-	 */
-	if ((fio_option_is_set(to, ioprio) || fio_option_is_set(to, ioprio_class)) &&
-			o->cmdprio_percentage != 0) {
-		log_err("%s: cmdprio_percentage option and mutually exclusive "
-				"prio or prioclass option is set, exiting\n", to->name);
+
+	ret = fio_cmdprio_init(td, cmdprio, &ld->use_cmdprio);
+	if (ret) {
 		td_verror(td, EINVAL, "fio_libaio_init");
 		return 1;
 	}
+
 	return 0;
 }
 
diff --git a/fio.1 b/fio.1
index 87ca8e73..3611da98 100644
--- a/fio.1
+++ b/fio.1
@@ -1962,13 +1962,13 @@ In addition, there are some parameters which are only valid when a specific
 with the caveat that when used on the command line, they must come after the
 \fBioengine\fR that defines them is selected.
 .TP
-.BI (io_uring,libaio)cmdprio_percentage \fR=\fPint
-Set the percentage of I/O that will be issued with higher priority by setting
-the priority bit. Non-read I/O is likely unaffected by ``cmdprio_percentage``.
-This option cannot be used with the `prio` or `prioclass` options. For this
-option to set the priority bit properly, NCQ priority must be supported and
-enabled and `direct=1' option must be used. fio must also be run as the root
-user.
+.BI (io_uring,libaio)cmdprio_percentage \fR=\fPint[,int]
+Set the percentage of I/O that will be issued with the highest priority.
+Default: 0. A single value applies to reads and writes. Comma-separated
+values may be specified for reads and writes. This option cannot be used
+with the `prio` or `prioclass` options. For this option to be effective,
+NCQ priority must be supported and enabled, and `direct=1' option must be
+used. fio must also be run as the root user.
 .TP
 .BI (io_uring)fixedbufs
 If fio is asked to do direct IO, then Linux will map pages for each IO call, and
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 08/11] libaio,io_uring: introduce cmdprio_bssplit
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (6 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 06/11] libaio,io_uring: improve cmdprio_percentage option Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 09/11] libaio,io_uring: relax cmdprio_percentage constraints Niklas Cassel
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

The cmdprio_percentage, cmdprio_class and cmdprio options allow
specifying different values for read and write operations. This enables
various IO priority issuing patterns even uner a mixed read-write
workload but does not allow differentiation within read and write
I/O operation types with different sizes when the bssplit option is
used.

Introduce the cmdprio_bssplit option to complement the use of the
bssplit option.  This new option has the same format as the bssplit
option, but the percentage values indicate the percentage of I/O
operations with a particular block size that must be issued with the
priority class and value specified by cmdprio_class and cmdprio.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 HOWTO                        |  29 ++++++---
 engines/cmdprio.h            | 113 ++++++++++++++++++++++++++++++++++-
 engines/io_uring.c           |  29 ++++++++-
 engines/libaio.c             |  29 ++++++++-
 fio.1                        |  34 +++++++----
 tools/fiograph/fiograph.conf |   4 +-
 6 files changed, 210 insertions(+), 28 deletions(-)

diff --git a/HOWTO b/HOWTO
index 8b7d4957..1853f56a 100644
--- a/HOWTO
+++ b/HOWTO
@@ -2175,23 +2175,38 @@ with the caveat that when used on the command line, they must come after the
 .. option:: cmdprio_class=int[,int] : [io_uring] [libaio]
 
 	Set the I/O priority class to use for I/Os that must be issued with
-	a priority when :option:`cmdprio_percentage` is set. If not specified
-	when :option:`cmdprio_percentage` is set, this defaults to the highest
-	priority class. A single value applies to reads and writes.
-	Comma-separated values may be specified for reads and writes. See
-	:manpage:`ionice(1)`. See also the :option:`prioclass` option.
+	a priority when :option:`cmdprio_percentage` or
+	:option:`cmdprio_bssplit` is set. If not specified when
+	:option:`cmdprio_percentage` or :option:`cmdprio_bssplit` is set,
+	this defaults to the highest priority class. A single value applies
+	to reads and writes. Comma-separated values may be specified for
+	reads and writes. See :manpage:`ionice(1)`. See also the
+	:option:`prioclass` option.
 
 .. option:: cmdprio=int[,int] : [io_uring] [libaio]
 
 	Set the I/O priority value to use for I/Os that must be issued with
-	a priority when :option:`cmdprio_percentage` is set. If not specified
-	when :option:`cmdprio_percentage` is set, this defaults to 0.
+	a priority when :option:`cmdprio_percentage` or
+	:option:`cmdprio_bssplit` is set. If not specified when
+	:option:`cmdprio_percentage` or :option:`cmdprio_bssplit` is set,
+	this defaults to 0.
 	Linux limits us to a positive value between 0 and 7, with 0 being the
 	highest. A single value applies to reads and writes. Comma-separated
 	values may be specified for reads and writes. See :manpage:`ionice(1)`.
 	Refer to an appropriate manpage for other operating systems since
 	meaning of priority may differ. See also the :option:`prio` option.
 
+.. option:: cmdprio_bssplit=str[,str] : [io_uring] [libaio]
+	To get a finer control over I/O priority, this option allows
+	specifying the percentage of IOs that must have a priority set
+	depending on the block size of the IO. This option is useful only
+	when used together with the :option:`bssplit` option, that is,
+	multiple different block sizes are used for reads and writes.
+	The format for this option is the same as the format of the
+	:option:`bssplit` option, with the exception that values for
+	trim IOs are ignored. This option is mutually exclusive with the
+	:option:`cmdprio_percentage` option.
+
 .. option:: fixedbufs : [io_uring]
 
     If fio is asked to do direct IO, then Linux will map pages for each
diff --git a/engines/cmdprio.h b/engines/cmdprio.h
index e3b42182..8acdb0b3 100644
--- a/engines/cmdprio.h
+++ b/engines/cmdprio.h
@@ -12,18 +12,106 @@ struct cmdprio {
 	unsigned int percentage[DDIR_RWDIR_CNT];
 	unsigned int class[DDIR_RWDIR_CNT];
 	unsigned int level[DDIR_RWDIR_CNT];
+	unsigned int bssplit_nr[DDIR_RWDIR_CNT];
+	struct bssplit *bssplit[DDIR_RWDIR_CNT];
 };
 
+static int fio_cmdprio_bssplit_ddir(struct thread_options *to, void *cb_arg,
+				    enum fio_ddir ddir, char *str, bool data)
+{
+	struct cmdprio *cmdprio = cb_arg;
+	struct split split;
+	unsigned int i;
+
+	if (ddir == DDIR_TRIM)
+		return 0;
+
+	memset(&split, 0, sizeof(split));
+
+	if (split_parse_ddir(to, &split, str, data, BSSPLIT_MAX))
+		return 1;
+	if (!split.nr)
+		return 0;
+
+	cmdprio->bssplit_nr[ddir] = split.nr;
+	cmdprio->bssplit[ddir] = malloc(split.nr * sizeof(struct bssplit));
+	if (!cmdprio->bssplit[ddir])
+		return 1;
+
+	for (i = 0; i < split.nr; i++) {
+		cmdprio->bssplit[ddir][i].bs = split.val1[i];
+		if (split.val2[i] == -1U) {
+			cmdprio->bssplit[ddir][i].perc = 0;
+		} else {
+			if (split.val2[i] > 100)
+				cmdprio->bssplit[ddir][i].perc = 100;
+			else
+				cmdprio->bssplit[ddir][i].perc = split.val2[i];
+		}
+	}
+
+	return 0;
+}
+
+static int fio_cmdprio_bssplit_parse(struct thread_data *td, const char *input,
+				     struct cmdprio *cmdprio)
+{
+	char *str, *p;
+	int i, ret = 0;
+
+	p = str = strdup(input);
+
+	strip_blank_front(&str);
+	strip_blank_end(str);
+
+	ret = str_split_parse(td, str, fio_cmdprio_bssplit_ddir, cmdprio, false);
+
+	if (parse_dryrun()) {
+		for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+			free(cmdprio->bssplit[i]);
+			cmdprio->bssplit[i] = NULL;
+			cmdprio->bssplit_nr[i] = 0;
+		}
+	}
+
+	free(p);
+	return ret;
+}
+
+static inline int fio_cmdprio_percentage(struct cmdprio *cmdprio,
+					 struct io_u *io_u)
+{
+	enum fio_ddir ddir = io_u->ddir;
+	unsigned int p = cmdprio->percentage[ddir];
+	int i;
+
+	/*
+	 * If cmdprio_percentage option was specified, then use that
+	 * percentage. Otherwise, use cmdprio_bssplit percentages depending
+	 * on the IO size.
+	 */
+	if (p)
+		return p;
+
+	for (i = 0; i < cmdprio->bssplit_nr[ddir]; i++) {
+		if (cmdprio->bssplit[ddir][i].bs == io_u->buflen)
+			return cmdprio->bssplit[ddir][i].perc;
+	}
+
+	return 0;
+}
+
 static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
 			    bool *has_cmdprio)
 {
 	struct thread_options *to = &td->o;
 	bool has_cmdprio_percentage = false;
+	bool has_cmdprio_bssplit = false;
 	int i;
 
 	/*
-	 * If cmdprio_percentage is set and cmdprio_class is not set,
-	 * default to RT priority class.
+	 * If cmdprio_percentage/cmdprio_bssplit is set and cmdprio_class
+	 * is not set, default to RT priority class.
 	 */
 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
 		if (cmdprio->percentage[i]) {
@@ -31,6 +119,11 @@ static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
 				cmdprio->class[i] = IOPRIO_CLASS_RT;
 			has_cmdprio_percentage = true;
 		}
+		if (cmdprio->bssplit_nr[i]) {
+			if (!cmdprio->class[i])
+				cmdprio->class[i] = IOPRIO_CLASS_RT;
+			has_cmdprio_bssplit = true;
+		}
 	}
 
 	/*
@@ -44,8 +137,22 @@ static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
 			to->name);
 		return 1;
 	}
+	if (has_cmdprio_bssplit &&
+	    (fio_option_is_set(to, ioprio) ||
+	     fio_option_is_set(to, ioprio_class))) {
+		log_err("%s: cmdprio_bssplit option and mutually exclusive "
+			"prio or prioclass option is set, exiting\n",
+			to->name);
+		return 1;
+	}
+	if (has_cmdprio_percentage && has_cmdprio_bssplit) {
+		log_err("%s: cmdprio_percentage and cmdprio_bssplit options "
+			"are mutually exclusive\n",
+			to->name);
+		return 1;
+	}
 
-	*has_cmdprio = has_cmdprio_percentage;
+	*has_cmdprio = has_cmdprio_percentage || has_cmdprio_bssplit;
 
 	return 0;
 }
diff --git a/engines/io_uring.c b/engines/io_uring.c
index 1591ee4e..57124d22 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -75,7 +75,7 @@ struct ioring_data {
 };
 
 struct ioring_options {
-	void *pad;
+	struct thread_data *td;
 	unsigned int hipri;
 	struct cmdprio cmdprio;
 	unsigned int fixedbufs;
@@ -108,6 +108,15 @@ static int fio_ioring_sqpoll_cb(void *data, unsigned long long *val)
 	return 0;
 }
 
+static int str_cmdprio_bssplit_cb(void *data, const char *input)
+{
+	struct ioring_options *o = data;
+	struct thread_data *td = o->td;
+	struct cmdprio *cmdprio = &o->cmdprio;
+
+	return fio_cmdprio_bssplit_parse(td, input, cmdprio);
+}
+
 static struct fio_option options[] = {
 	{
 		.name	= "hipri",
@@ -163,6 +172,16 @@ static struct fio_option options[] = {
 		.category = FIO_OPT_C_ENGINE,
 		.group	= FIO_OPT_G_IOURING,
 	},
+	{
+		.name   = "cmdprio_bssplit",
+		.lname  = "Priority percentage block size split",
+		.type   = FIO_OPT_STR_ULL,
+		.cb     = str_cmdprio_bssplit_cb,
+		.off1   = offsetof(struct ioring_options, cmdprio.bssplit),
+		.help   = "Set priority percentages for different block sizes",
+		.category = FIO_OPT_C_ENGINE,
+		.group	= FIO_OPT_G_IOURING,
+	},
 #else
 	{
 		.name	= "cmdprio_percentage",
@@ -182,6 +201,12 @@ static struct fio_option options[] = {
 		.type	= FIO_OPT_UNSUPPORTED,
 		.help	= "Your platform does not support I/O priority classes",
 	},
+	{
+		.name   = "cmdprio_bssplit",
+		.lname  = "Priority percentage block size split",
+		.type	= FIO_OPT_UNSUPPORTED,
+		.help	= "Your platform does not support I/O priority classes",
+	},
 #endif
 	{
 		.name	= "fixedbufs",
@@ -432,7 +457,7 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 	struct io_uring_sqe *sqe = &ld->sqes[io_u->index];
 	struct cmdprio *cmdprio = &o->cmdprio;
 	enum fio_ddir ddir = io_u->ddir;
-	unsigned int p = cmdprio->percentage[ddir];
+	unsigned int p = fio_cmdprio_percentage(cmdprio, io_u);
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
 		sqe->ioprio =
diff --git a/engines/libaio.c b/engines/libaio.c
index 8b965fe2..9fba3b12 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -56,12 +56,21 @@ struct libaio_data {
 };
 
 struct libaio_options {
-	void *pad;
+	struct thread_data *td;
 	unsigned int userspace_reap;
 	struct cmdprio cmdprio;
 	unsigned int nowait;
 };
 
+static int str_cmdprio_bssplit_cb(void *data, const char *input)
+{
+	struct libaio_options *o = data;
+	struct thread_data *td = o->td;
+	struct cmdprio *cmdprio = &o->cmdprio;
+
+	return fio_cmdprio_bssplit_parse(td, input, cmdprio);
+}
+
 static struct fio_option options[] = {
 	{
 		.name	= "userspace_reap",
@@ -117,6 +126,16 @@ static struct fio_option options[] = {
 		.category = FIO_OPT_C_ENGINE,
 		.group	= FIO_OPT_G_LIBAIO,
 	},
+	{
+		.name   = "cmdprio_bssplit",
+		.lname  = "Priority percentage block size split",
+		.type   = FIO_OPT_STR_ULL,
+		.cb     = str_cmdprio_bssplit_cb,
+		.off1   = offsetof(struct libaio_options, cmdprio.bssplit),
+		.help   = "Set priority percentages for different block sizes",
+		.category = FIO_OPT_C_ENGINE,
+		.group	= FIO_OPT_G_LIBAIO,
+	},
 #else
 	{
 		.name	= "cmdprio_percentage",
@@ -136,6 +155,12 @@ static struct fio_option options[] = {
 		.type	= FIO_OPT_UNSUPPORTED,
 		.help	= "Your platform does not support I/O priority classes",
 	},
+	{
+		.name   = "cmdprio_bssplit",
+		.lname  = "Priority percentage block size split",
+		.type	= FIO_OPT_UNSUPPORTED,
+		.help	= "Your platform does not support I/O priority classes",
+	},
 #endif
 	{
 		.name	= "nowait",
@@ -185,7 +210,7 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 	struct libaio_options *o = td->eo;
 	struct cmdprio *cmdprio = &o->cmdprio;
 	enum fio_ddir ddir = io_u->ddir;
-	unsigned int p = cmdprio->percentage[ddir];
+	unsigned int p = fio_cmdprio_percentage(cmdprio, io_u);
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
 		io_u->iocb.aio_reqprio =
diff --git a/fio.1 b/fio.1
index 09b97de3..415a91bb 100644
--- a/fio.1
+++ b/fio.1
@@ -1972,21 +1972,31 @@ used. fio must also be run as the root user.
 .TP
 .BI (io_uring,libaio)cmdprio_class \fR=\fPint[,int]
 Set the I/O priority class to use for I/Os that must be issued with a
-priority when \fBcmdprio_percentage\fR is set. If not specified when
-\fBcmdprio_percentage\fR is set, this defaults to the highest priority
-class. A single value applies to reads and writes. Comma-separated
-values may be specified for reads and writes. See man \fBionice\fR\|(1).
-See also the \fBprioclass\fR option.
+priority when \fBcmdprio_percentage\fR or \fBcmdprio_bssplit\fR is set.
+If not specified when \fBcmdprio_percentage\fR or \fBcmdprio_bssplit\fR
+is set, this defaults to the highest priority class. A single value applies
+to reads and writes. Comma-separated values may be specified for reads and
+writes. See man \fBionice\fR\|(1). See also the \fBprioclass\fR option.
 .TP
 .BI (io_uring,libaio)cmdprio \fR=\fPint[,int]
 Set the I/O priority value to use for I/Os that must be issued with a
-priority when \fBcmdprio_percentage\fR is set. If not specified when
-\fBcmdprio_percentage\fR is set, this defaults to 0. Linux limits us to
-a positive value between 0 and 7, with 0 being the highest. A single
-value applies to reads and writes. Comma-separated values may be specified
-for reads and writes. See man \fBionice\fR\|(1). Refer to an appropriate
-manpage for other operating systems since the meaning of priority may differ.
-See also the \fBprio\fR option.
+priority when \fBcmdprio_percentage\fR or \fBcmdprio_bssplit\fR is set.
+If not specified when \fBcmdprio_percentage\fR or \fBcmdprio_bssplit\fR
+is set, this defaults to 0. Linux limits us to a positive value between
+0 and 7, with 0 being the highest. A single value applies to reads and writes.
+Comma-separated values may be specified for reads and writes. See man
+\fBionice\fR\|(1). Refer to an appropriate manpage for other operating systems
+since the meaning of priority may differ. See also the \fBprio\fR option.
+.TP
+.BI (io_uring,libaio)cmdprio_bssplit \fR=\fPstr[,str]
+To get a finer control over I/O priority, this option allows specifying
+the percentage of IOs that must have a priority set depending on the block
+size of the IO. This option is useful only when used together with the option
+\fBbssplit\fR, that is, multiple different block sizes are used for reads and
+writes. The format for this option is the same as the format of the
+\fBbssplit\fR option, with the exception that values for trim IOs are
+ignored. This option is mutually exclusive with the \fBcmdprio_percentage\fR
+option.
 .TP
 .BI (io_uring)fixedbufs
 If fio is asked to do direct IO, then Linux will map pages for each IO call, and
diff --git a/tools/fiograph/fiograph.conf b/tools/fiograph/fiograph.conf
index 5ba59c52..cfd2fd8e 100644
--- a/tools/fiograph/fiograph.conf
+++ b/tools/fiograph/fiograph.conf
@@ -51,10 +51,10 @@ specific_options=https  http_host  http_user  http_pass  http_s3_key  http_s3_ke
 specific_options=ime_psync  ime_psyncv
 
 [ioengine_io_uring]
-specific_options=hipri  cmdprio_percentage  cmdprio_class  cmdprio  fixedbufs  registerfiles  sqthread_poll  sqthread_poll_cpu  nonvectored  uncached  nowait  force_async
+specific_options=hipri  cmdprio_percentage  cmdprio_class  cmdprio  cmdprio_bssplit  fixedbufs  registerfiles  sqthread_poll  sqthread_poll_cpu  nonvectored  uncached  nowait  force_async
 
 [ioengine_libaio]
-specific_options=userspace_reap  cmdprio_percentage  cmdprio_class  cmdprio  nowait
+specific_options=userspace_reap  cmdprio_percentage  cmdprio_class  cmdprio  cmdprio_bssplit  nowait
 
 [ioengine_libcufile]
 specific_options=gpu_dev_ids  cuda_io
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 10/11] fio: Introduce the log_prio option
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (8 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 09/11] libaio,io_uring: relax cmdprio_percentage constraints Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 11/11] examples: add examples for cmdprio_* IO priority options Niklas Cassel
  2021-09-03 16:12 ` [PATCH v2 00/11] Improve io_uring and libaio IO priority support Jens Axboe
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

Introduce the log_prio option to expand priority logging from just a
single bit information (priority high vs low) to the full value of the
priority value used to execute IOs. When this option is set, the
priority value is printed as a 16-bits hexadecimal value combining
the I/O priority class and priority level as defined by the
ioprio_value() helper.

Similarly to the log_offset option, this option does not result in
actual I/O priority logging when log_avg_msec is set.

This patch also fixes a problem with the IO_U_F_PRIORITY flag, namely
that this flag is used to indicate that the IO is being executed with a
high priority on the device while at the same time indicating how to
account for the IO completion latency (high_prio clat vs low_prio clat).
With the introduction of the cmdprio_class and cmdprio options, these
assumptions are not necesarilly compatible anymore.

These problems are addressed as follows:
* The priority_bit field of struct iosample is replaced with the
  16-bits priority field representing the full io_u->ioprio value. When
  log_prio is set, the priority field value is logged as is. When
  log_prio is not set, 1 is logged as the entry's priority field if the
  sample priority class is IOPRIO_CLASS_RT, and 0 otherwise.
* IO_U_F_PRIORITY is renamed to IO_U_F_HIGH_PRIO to indicate that a job
  IO has the highest priority within the job context and so must be
  accounted as such using high_prio clat.

While fio final statistics only show accounting of high vs low IO
completion latency statistics, the log_prio option allows a user to
perform more detailed statistical analysis of a workload using
multiple different IO priorities.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 cconv.c              |  2 ++
 client.c             |  2 ++
 engines/filecreate.c |  2 +-
 engines/filedelete.c |  2 +-
 engines/filestat.c   |  2 +-
 engines/io_uring.c   |  6 ++--
 engines/libaio.c     |  5 +--
 eta.c                |  2 +-
 fio.1                | 15 +++++++--
 init.c               |  4 +++
 io_u.c               | 14 ++++++---
 io_u.h               | 10 ++++--
 iolog.c              | 45 ++++++++++++++++++++------
 iolog.h              | 16 ++++++++--
 options.c            | 10 ++++++
 os/os-android.h      |  5 +++
 os/os-linux.h        |  5 +++
 os/os.h              |  3 ++
 server.h             |  3 +-
 stat.c               | 75 +++++++++++++++++++++++---------------------
 stat.h               |  9 +++---
 thread_options.h     |  4 +++
 22 files changed, 170 insertions(+), 71 deletions(-)

diff --git a/cconv.c b/cconv.c
index e3a8c27c..2dc5274e 100644
--- a/cconv.c
+++ b/cconv.c
@@ -192,6 +192,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
 	o->log_hist_coarseness = le32_to_cpu(top->log_hist_coarseness);
 	o->log_max = le32_to_cpu(top->log_max);
 	o->log_offset = le32_to_cpu(top->log_offset);
+	o->log_prio = le32_to_cpu(top->log_prio);
 	o->log_gz = le32_to_cpu(top->log_gz);
 	o->log_gz_store = le32_to_cpu(top->log_gz_store);
 	o->log_unix_epoch = le32_to_cpu(top->log_unix_epoch);
@@ -417,6 +418,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
 	top->log_avg_msec = cpu_to_le32(o->log_avg_msec);
 	top->log_max = cpu_to_le32(o->log_max);
 	top->log_offset = cpu_to_le32(o->log_offset);
+	top->log_prio = cpu_to_le32(o->log_prio);
 	top->log_gz = cpu_to_le32(o->log_gz);
 	top->log_gz_store = cpu_to_le32(o->log_gz_store);
 	top->log_unix_epoch = cpu_to_le32(o->log_unix_epoch);
diff --git a/client.c b/client.c
index 29d8750a..8b230617 100644
--- a/client.c
+++ b/client.c
@@ -1679,6 +1679,7 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd,
 	ret->log_type		= le32_to_cpu(ret->log_type);
 	ret->compressed		= le32_to_cpu(ret->compressed);
 	ret->log_offset		= le32_to_cpu(ret->log_offset);
+	ret->log_prio		= le32_to_cpu(ret->log_prio);
 	ret->log_hist_coarseness = le32_to_cpu(ret->log_hist_coarseness);
 
 	if (*store_direct)
@@ -1696,6 +1697,7 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd,
 		s->data.val	= le64_to_cpu(s->data.val);
 		s->__ddir	= __le32_to_cpu(s->__ddir);
 		s->bs		= le64_to_cpu(s->bs);
+		s->priority	= le16_to_cpu(s->priority);
 
 		if (ret->log_offset) {
 			struct io_sample_offset *so = (void *) s;
diff --git a/engines/filecreate.c b/engines/filecreate.c
index 16c64928..4bb13c34 100644
--- a/engines/filecreate.c
+++ b/engines/filecreate.c
@@ -49,7 +49,7 @@ static int open_file(struct thread_data *td, struct fio_file *f)
 		uint64_t nsec;
 
 		nsec = ntime_since_now(&start);
-		add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0);
+		add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, false);
 	}
 
 	return 0;
diff --git a/engines/filedelete.c b/engines/filedelete.c
index 64c58639..e882ccf0 100644
--- a/engines/filedelete.c
+++ b/engines/filedelete.c
@@ -51,7 +51,7 @@ static int delete_file(struct thread_data *td, struct fio_file *f)
 		uint64_t nsec;
 
 		nsec = ntime_since_now(&start);
-		add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0);
+		add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, false);
 	}
 
 	return 0;
diff --git a/engines/filestat.c b/engines/filestat.c
index 405f028d..00311247 100644
--- a/engines/filestat.c
+++ b/engines/filestat.c
@@ -125,7 +125,7 @@ static int stat_file(struct thread_data *td, struct fio_file *f)
 		uint64_t nsec;
 
 		nsec = ntime_since_now(&start);
-		add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0);
+		add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, false);
 	}
 
 	return 0;
diff --git a/engines/io_uring.c b/engines/io_uring.c
index df2d6c4c..27a4a678 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -463,7 +463,7 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 			 * than the priority set by "prio" and "prioclass"
 			 * options.
 			 */
-			io_u->flags |= IO_U_F_PRIORITY;
+			io_u->flags |= IO_U_F_HIGH_PRIO;
 		}
 	} else {
 		sqe->ioprio = td->ioprio;
@@ -474,9 +474,11 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 			 * is higher (has a lower value) than the async IO
 			 * priority.
 			 */
-			io_u->flags |= IO_U_F_PRIORITY;
+			io_u->flags |= IO_U_F_HIGH_PRIO;
 		}
 	}
+
+	io_u->ioprio = sqe->ioprio;
 }
 
 static enum fio_q_status fio_ioring_queue(struct thread_data *td,
diff --git a/engines/libaio.c b/engines/libaio.c
index 62c8aed7..dd655355 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -215,6 +215,7 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 		ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
+		io_u->ioprio = cmdprio_value;
 		io_u->iocb.aio_reqprio = cmdprio_value;
 		io_u->iocb.u.c.flags |= IOCB_FLAG_IOPRIO;
 		if (!td->ioprio || cmdprio_value < td->ioprio) {
@@ -222,7 +223,7 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 			 * The async IO priority is higher (has a lower value)
 			 * than the default context priority.
 			 */
-			io_u->flags |= IO_U_F_PRIORITY;
+			io_u->flags |= IO_U_F_HIGH_PRIO;
 		}
 	} else if (td->ioprio && td->ioprio < cmdprio_value) {
 		/*
@@ -230,7 +231,7 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 		 * and this priority is higher (has a lower value) than the
 		 * async IO priority.
 		 */
-		io_u->flags |= IO_U_F_PRIORITY;
+		io_u->flags |= IO_U_F_HIGH_PRIO;
 	}
 }
 
diff --git a/eta.c b/eta.c
index db13cb18..ea1781f3 100644
--- a/eta.c
+++ b/eta.c
@@ -509,7 +509,7 @@ bool calc_thread_status(struct jobs_eta *je, int force)
 		memcpy(&rate_prev_time, &now, sizeof(now));
 		regrow_agg_logs();
 		for_each_rw_ddir(ddir) {
-			add_agg_sample(sample_val(je->rate[ddir]), ddir, 0, 0);
+			add_agg_sample(sample_val(je->rate[ddir]), ddir, 0);
 		}
 	}
 
diff --git a/fio.1 b/fio.1
index 415a91bb..03fddffb 100644
--- a/fio.1
+++ b/fio.1
@@ -3266,6 +3266,11 @@ If this is set, the iolog options will include the byte offset for the I/O
 entry as well as the other data values. Defaults to 0 meaning that
 offsets are not present in logs. Also see \fBLOG FILE FORMATS\fR section.
 .TP
+.BI log_prio \fR=\fPbool
+If this is set, the iolog options will include the I/O priority for the I/O
+entry as well as the other data values. Defaults to 0 meaning that
+I/O priorities are not present in logs. Also see \fBLOG FILE FORMATS\fR section.
+.TP
 .BI log_compression \fR=\fPint
 If this is set, fio will compress the I/O logs as it goes, to keep the
 memory footprint lower. When a log reaches the specified size, that chunk is
@@ -4199,8 +4204,14 @@ The entry's `block size' is always in bytes. The `offset' is the position in byt
 from the start of the file for that particular I/O. The logging of the offset can be
 toggled with \fBlog_offset\fR.
 .P
-`Command priority` is 0 for normal priority and 1 for high priority. This is controlled
-by the ioengine specific \fBcmdprio_percentage\fR.
+If \fBlog_prio\fR is not set, the entry's `Command priority` is 1 for an IO executed
+with the highest RT priority class (\fBprioclass\fR=1 or \fBcmdprio_class\fR=1) and 0
+otherwise. This is controlled by the \fBprioclass\fR option and the ioengine specific
+\fBcmdprio_percentage\fR \fBcmdprio_class\fR options. If \fBlog_prio\fR is set, the
+entry's `Command priority` is the priority set for the IO, as a 16-bits hexadecimal
+number with the lowest 13 bits indicating the priority value (\fBprio\fR and
+\fBcmdprio\fR options) and the highest 3 bits indicating the IO priority class
+(\fBprioclass\fR and \fBcmdprio_class\fR options).
 .P
 Fio defaults to logging every individual I/O but when windowed logging is set
 through \fBlog_avg_msec\fR, either the average (by default) or the maximum
diff --git a/init.c b/init.c
index 871fb5ad..ec1a2cac 100644
--- a/init.c
+++ b/init.c
@@ -1583,6 +1583,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 			.hist_coarseness = o->log_hist_coarseness,
 			.log_type = IO_LOG_TYPE_LAT,
 			.log_offset = o->log_offset,
+			.log_prio = o->log_prio,
 			.log_gz = o->log_gz,
 			.log_gz_store = o->log_gz_store,
 		};
@@ -1616,6 +1617,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 			.hist_coarseness = o->log_hist_coarseness,
 			.log_type = IO_LOG_TYPE_HIST,
 			.log_offset = o->log_offset,
+			.log_prio = o->log_prio,
 			.log_gz = o->log_gz,
 			.log_gz_store = o->log_gz_store,
 		};
@@ -1647,6 +1649,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 			.hist_coarseness = o->log_hist_coarseness,
 			.log_type = IO_LOG_TYPE_BW,
 			.log_offset = o->log_offset,
+			.log_prio = o->log_prio,
 			.log_gz = o->log_gz,
 			.log_gz_store = o->log_gz_store,
 		};
@@ -1678,6 +1681,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 			.hist_coarseness = o->log_hist_coarseness,
 			.log_type = IO_LOG_TYPE_IOPS,
 			.log_offset = o->log_offset,
+			.log_prio = o->log_prio,
 			.log_gz = o->log_gz,
 			.log_gz_store = o->log_gz_store,
 		};
diff --git a/io_u.c b/io_u.c
index 696d25cd..5289b5d1 100644
--- a/io_u.c
+++ b/io_u.c
@@ -1595,7 +1595,7 @@ again:
 		assert(io_u->flags & IO_U_F_FREE);
 		io_u_clear(td, io_u, IO_U_F_FREE | IO_U_F_NO_FILE_PUT |
 				 IO_U_F_TRIMMED | IO_U_F_BARRIER |
-				 IO_U_F_VER_LIST | IO_U_F_PRIORITY);
+				 IO_U_F_VER_LIST | IO_U_F_HIGH_PRIO);
 
 		io_u->error = 0;
 		io_u->acct_ddir = -1;
@@ -1799,6 +1799,10 @@ struct io_u *get_io_u(struct thread_data *td)
 	io_u->xfer_buf = io_u->buf;
 	io_u->xfer_buflen = io_u->buflen;
 
+	/*
+	 * Remember the issuing context priority. The IO engine may change this.
+	 */
+	io_u->ioprio = td->ioprio;
 out:
 	assert(io_u->file);
 	if (!td_io_prep(td, io_u)) {
@@ -1884,7 +1888,8 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
 		unsigned long long tnsec;
 
 		tnsec = ntime_since(&io_u->start_time, &icd->time);
-		add_lat_sample(td, idx, tnsec, bytes, io_u->offset, io_u_is_prio(io_u));
+		add_lat_sample(td, idx, tnsec, bytes, io_u->offset,
+			       io_u->ioprio, io_u_is_high_prio(io_u));
 
 		if (td->flags & TD_F_PROFILE_OPS) {
 			struct prof_io_ops *ops = &td->prof_io_ops;
@@ -1905,7 +1910,8 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u,
 
 	if (ddir_rw(idx)) {
 		if (!td->o.disable_clat) {
-			add_clat_sample(td, idx, llnsec, bytes, io_u->offset, io_u_is_prio(io_u));
+			add_clat_sample(td, idx, llnsec, bytes, io_u->offset,
+					io_u->ioprio, io_u_is_high_prio(io_u));
 			io_u_mark_latency(td, llnsec);
 		}
 
@@ -2162,7 +2168,7 @@ void io_u_queued(struct thread_data *td, struct io_u *io_u)
 			td = td->parent;
 
 		add_slat_sample(td, io_u->ddir, slat_time, io_u->xfer_buflen,
-				io_u->offset, io_u_is_prio(io_u));
+				io_u->offset, io_u->ioprio);
 	}
 }
 
diff --git a/io_u.h b/io_u.h
index d4c5be43..bdbac525 100644
--- a/io_u.h
+++ b/io_u.h
@@ -21,7 +21,7 @@ enum {
 	IO_U_F_TRIMMED		= 1 << 5,
 	IO_U_F_BARRIER		= 1 << 6,
 	IO_U_F_VER_LIST		= 1 << 7,
-	IO_U_F_PRIORITY		= 1 << 8,
+	IO_U_F_HIGH_PRIO	= 1 << 8,
 };
 
 /*
@@ -46,6 +46,11 @@ struct io_u {
 	 */
 	unsigned short numberio;
 
+	/*
+	 * IO priority.
+	 */
+	unsigned short ioprio;
+
 	/*
 	 * Allocated/set buffer and length
 	 */
@@ -188,7 +193,6 @@ static inline enum fio_ddir acct_ddir(struct io_u *io_u)
 	td_flags_clear((td), &(io_u->flags), (val))
 #define io_u_set(td, io_u, val)		\
 	td_flags_set((td), &(io_u)->flags, (val))
-#define io_u_is_prio(io_u)	\
-	(io_u->flags & (unsigned int) IO_U_F_PRIORITY) != 0
+#define io_u_is_high_prio(io_u)	(io_u->flags & IO_U_F_HIGH_PRIO)
 
 #endif
diff --git a/iolog.c b/iolog.c
index 26501b4a..1aeb7a76 100644
--- a/iolog.c
+++ b/iolog.c
@@ -737,6 +737,7 @@ void setup_log(struct io_log **log, struct log_params *p,
 	INIT_FLIST_HEAD(&l->io_logs);
 	l->log_type = p->log_type;
 	l->log_offset = p->log_offset;
+	l->log_prio = p->log_prio;
 	l->log_gz = p->log_gz;
 	l->log_gz_store = p->log_gz_store;
 	l->avg_msec = p->avg_msec;
@@ -769,6 +770,8 @@ void setup_log(struct io_log **log, struct log_params *p,
 
 	if (l->log_offset)
 		l->log_ddir_mask = LOG_OFFSET_SAMPLE_BIT;
+	if (l->log_prio)
+		l->log_ddir_mask |= LOG_PRIO_SAMPLE_BIT;
 
 	INIT_FLIST_HEAD(&l->chunk_list);
 
@@ -895,33 +898,55 @@ static void flush_hist_samples(FILE *f, int hist_coarseness, void *samples,
 void flush_samples(FILE *f, void *samples, uint64_t sample_size)
 {
 	struct io_sample *s;
-	int log_offset;
+	int log_offset, log_prio;
 	uint64_t i, nr_samples;
+	unsigned int prio_val;
+	const char *fmt;
 
 	if (!sample_size)
 		return;
 
 	s = __get_sample(samples, 0, 0);
 	log_offset = (s->__ddir & LOG_OFFSET_SAMPLE_BIT) != 0;
+	log_prio = (s->__ddir & LOG_PRIO_SAMPLE_BIT) != 0;
+
+	if (log_offset) {
+		if (log_prio)
+			fmt = "%lu, %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
+		else
+			fmt = "%lu, %" PRId64 ", %u, %llu, %llu, %u\n";
+	} else {
+		if (log_prio)
+			fmt = "%lu, %" PRId64 ", %u, %llu, 0x%04x\n";
+		else
+			fmt = "%lu, %" PRId64 ", %u, %llu, %u\n";
+	}
 
 	nr_samples = sample_size / __log_entry_sz(log_offset);
 
 	for (i = 0; i < nr_samples; i++) {
 		s = __get_sample(samples, log_offset, i);
 
+		if (log_prio)
+			prio_val = s->priority;
+		else
+			prio_val = ioprio_value_is_class_rt(s->priority);
+
 		if (!log_offset) {
-			fprintf(f, "%lu, %" PRId64 ", %u, %llu, %u\n",
-					(unsigned long) s->time,
-					s->data.val,
-					io_sample_ddir(s), (unsigned long long) s->bs, s->priority_bit);
+			fprintf(f, fmt,
+				(unsigned long) s->time,
+				s->data.val,
+				io_sample_ddir(s), (unsigned long long) s->bs,
+				prio_val);
 		} else {
 			struct io_sample_offset *so = (void *) s;
 
-			fprintf(f, "%lu, %" PRId64 ", %u, %llu, %llu, %u\n",
-					(unsigned long) s->time,
-					s->data.val,
-					io_sample_ddir(s), (unsigned long long) s->bs,
-					(unsigned long long) so->offset, s->priority_bit);
+			fprintf(f, fmt,
+				(unsigned long) s->time,
+				s->data.val,
+				io_sample_ddir(s), (unsigned long long) s->bs,
+				(unsigned long long) so->offset,
+				prio_val);
 		}
 	}
 }
diff --git a/iolog.h b/iolog.h
index 9e382cc0..7d66b7c4 100644
--- a/iolog.h
+++ b/iolog.h
@@ -42,7 +42,7 @@ struct io_sample {
 	uint64_t time;
 	union io_sample_data data;
 	uint32_t __ddir;
-	uint8_t priority_bit;
+	uint16_t priority;
 	uint64_t bs;
 };
 
@@ -104,6 +104,11 @@ struct io_log {
 	 */
 	unsigned int log_offset;
 
+	/*
+	 * Log I/O priorities
+	 */
+	unsigned int log_prio;
+
 	/*
 	 * Max size of log entries before a chunk is compressed
 	 */
@@ -145,7 +150,13 @@ struct io_log {
  * If the upper bit is set, then we have the offset as well
  */
 #define LOG_OFFSET_SAMPLE_BIT	0x80000000U
-#define io_sample_ddir(io)	((io)->__ddir & ~LOG_OFFSET_SAMPLE_BIT)
+/*
+ * If the bit following the upper bit is set, then we have the priority
+ */
+#define LOG_PRIO_SAMPLE_BIT	0x40000000U
+
+#define LOG_SAMPLE_BITS		(LOG_OFFSET_SAMPLE_BIT | LOG_PRIO_SAMPLE_BIT)
+#define io_sample_ddir(io)	((io)->__ddir & ~LOG_SAMPLE_BITS)
 
 static inline void io_sample_set_ddir(struct io_log *log,
 				      struct io_sample *io,
@@ -262,6 +273,7 @@ struct log_params {
 	int hist_coarseness;
 	int log_type;
 	int log_offset;
+	int log_prio;
 	int log_gz;
 	int log_gz_store;
 	int log_compress;
diff --git a/options.c b/options.c
index 708f3703..74ac1f3f 100644
--- a/options.c
+++ b/options.c
@@ -4292,6 +4292,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
 		.category = FIO_OPT_C_LOG,
 		.group	= FIO_OPT_G_INVALID,
 	},
+	{
+		.name	= "log_prio",
+		.lname	= "Log priority of IO",
+		.type	= FIO_OPT_BOOL,
+		.off1	= offsetof(struct thread_options, log_prio),
+		.help	= "Include priority value of IO for each log entry",
+		.def	= "0",
+		.category = FIO_OPT_C_LOG,
+		.group	= FIO_OPT_G_INVALID,
+	},
 #ifdef CONFIG_ZLIB
 	{
 		.name	= "log_compression",
diff --git a/os/os-android.h b/os/os-android.h
index f013172f..18eb39ce 100644
--- a/os/os-android.h
+++ b/os/os-android.h
@@ -184,6 +184,11 @@ static inline int ioprio_value(int ioprio_class, int ioprio)
 	return (ioprio_class << IOPRIO_CLASS_SHIFT) | ioprio;
 }
 
+static inline bool ioprio_value_is_class_rt(unsigned int priority)
+{
+	return (priority >> IOPRIO_CLASS_SHIFT) == IOPRIO_CLASS_RT;
+}
+
 static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
 {
 	return syscall(__NR_ioprio_set, which, who,
diff --git a/os/os-linux.h b/os/os-linux.h
index 12886037..808f1d02 100644
--- a/os/os-linux.h
+++ b/os/os-linux.h
@@ -129,6 +129,11 @@ static inline int ioprio_value(int ioprio_class, int ioprio)
 	return (ioprio_class << IOPRIO_CLASS_SHIFT) | ioprio;
 }
 
+static inline bool ioprio_value_is_class_rt(unsigned int priority)
+{
+	return (priority >> IOPRIO_CLASS_SHIFT) == IOPRIO_CLASS_RT;
+}
+
 static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
 {
 	return syscall(__NR_ioprio_set, which, who,
diff --git a/os/os.h b/os/os.h
index f2257a7c..827b61e9 100644
--- a/os/os.h
+++ b/os/os.h
@@ -117,6 +117,9 @@ static inline int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu_index)
 extern int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu);
 #endif
 
+#ifndef FIO_HAVE_IOPRIO_CLASS
+#define ioprio_value_is_class_rt(prio)	(false)
+#endif
 #ifndef FIO_HAVE_IOPRIO
 #define ioprio_value(prioclass, prio)	(0)
 #define ioprio_set(which, who, prioclass, prio)	(0)
diff --git a/server.h b/server.h
index daed057a..3ff32d9a 100644
--- a/server.h
+++ b/server.h
@@ -48,7 +48,7 @@ struct fio_net_cmd_reply {
 };
 
 enum {
-	FIO_SERVER_VER			= 92,
+	FIO_SERVER_VER			= 93,
 
 	FIO_SERVER_MAX_FRAGMENT_PDU	= 1024,
 	FIO_SERVER_MAX_CMD_MB		= 2048,
@@ -193,6 +193,7 @@ struct cmd_iolog_pdu {
 	uint32_t log_type;
 	uint32_t compressed;
 	uint32_t log_offset;
+	uint32_t log_prio;
 	uint32_t log_hist_coarseness;
 	uint8_t name[FIO_NET_NAME_MAX];
 	struct io_sample samples[0];
diff --git a/stat.c b/stat.c
index a8a96c85..99275620 100644
--- a/stat.c
+++ b/stat.c
@@ -2860,7 +2860,8 @@ static struct io_logs *get_cur_log(struct io_log *iolog)
 
 static void __add_log_sample(struct io_log *iolog, union io_sample_data data,
 			     enum fio_ddir ddir, unsigned long long bs,
-			     unsigned long t, uint64_t offset, uint8_t priority_bit)
+			     unsigned long t, uint64_t offset,
+			     unsigned int priority)
 {
 	struct io_logs *cur_log;
 
@@ -2879,7 +2880,7 @@ static void __add_log_sample(struct io_log *iolog, union io_sample_data data,
 		s->time = t + (iolog->td ? iolog->td->unix_epoch : 0);
 		io_sample_set_ddir(iolog, s, ddir);
 		s->bs = bs;
-		s->priority_bit = priority_bit;
+		s->priority = priority;
 
 		if (iolog->log_offset) {
 			struct io_sample_offset *so = (void *) s;
@@ -2956,7 +2957,7 @@ void reset_io_stats(struct thread_data *td)
 }
 
 static void __add_stat_to_log(struct io_log *iolog, enum fio_ddir ddir,
-			      unsigned long elapsed, bool log_max, uint8_t priority_bit)
+			      unsigned long elapsed, bool log_max)
 {
 	/*
 	 * Note an entry in the log. Use the mean from the logged samples,
@@ -2971,26 +2972,26 @@ static void __add_stat_to_log(struct io_log *iolog, enum fio_ddir ddir,
 		else
 			data.val = iolog->avg_window[ddir].mean.u.f + 0.50;
 
-		__add_log_sample(iolog, data, ddir, 0, elapsed, 0, priority_bit);
+		__add_log_sample(iolog, data, ddir, 0, elapsed, 0, 0);
 	}
 
 	reset_io_stat(&iolog->avg_window[ddir]);
 }
 
 static void _add_stat_to_log(struct io_log *iolog, unsigned long elapsed,
-			     bool log_max, uint8_t priority_bit)
+			     bool log_max)
 {
 	int ddir;
 
 	for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++)
-		__add_stat_to_log(iolog, ddir, elapsed, log_max, priority_bit);
+		__add_stat_to_log(iolog, ddir, elapsed, log_max);
 }
 
 static unsigned long add_log_sample(struct thread_data *td,
 				    struct io_log *iolog,
 				    union io_sample_data data,
 				    enum fio_ddir ddir, unsigned long long bs,
-				    uint64_t offset, uint8_t priority_bit)
+				    uint64_t offset, unsigned int ioprio)
 {
 	unsigned long elapsed, this_window;
 
@@ -3003,7 +3004,8 @@ static unsigned long add_log_sample(struct thread_data *td,
 	 * If no time averaging, just add the log sample.
 	 */
 	if (!iolog->avg_msec) {
-		__add_log_sample(iolog, data, ddir, bs, elapsed, offset, priority_bit);
+		__add_log_sample(iolog, data, ddir, bs, elapsed, offset,
+				 ioprio);
 		return 0;
 	}
 
@@ -3027,7 +3029,7 @@ static unsigned long add_log_sample(struct thread_data *td,
 			return diff;
 	}
 
-	__add_stat_to_log(iolog, ddir, elapsed, td->o.log_max != 0, priority_bit);
+	__add_stat_to_log(iolog, ddir, elapsed, td->o.log_max != 0);
 
 	iolog->avg_last[ddir] = elapsed - (elapsed % iolog->avg_msec);
 
@@ -3041,19 +3043,19 @@ void finalize_logs(struct thread_data *td, bool unit_logs)
 	elapsed = mtime_since_now(&td->epoch);
 
 	if (td->clat_log && unit_logs)
-		_add_stat_to_log(td->clat_log, elapsed, td->o.log_max != 0, 0);
+		_add_stat_to_log(td->clat_log, elapsed, td->o.log_max != 0);
 	if (td->slat_log && unit_logs)
-		_add_stat_to_log(td->slat_log, elapsed, td->o.log_max != 0, 0);
+		_add_stat_to_log(td->slat_log, elapsed, td->o.log_max != 0);
 	if (td->lat_log && unit_logs)
-		_add_stat_to_log(td->lat_log, elapsed, td->o.log_max != 0, 0);
+		_add_stat_to_log(td->lat_log, elapsed, td->o.log_max != 0);
 	if (td->bw_log && (unit_logs == per_unit_log(td->bw_log)))
-		_add_stat_to_log(td->bw_log, elapsed, td->o.log_max != 0, 0);
+		_add_stat_to_log(td->bw_log, elapsed, td->o.log_max != 0);
 	if (td->iops_log && (unit_logs == per_unit_log(td->iops_log)))
-		_add_stat_to_log(td->iops_log, elapsed, td->o.log_max != 0, 0);
+		_add_stat_to_log(td->iops_log, elapsed, td->o.log_max != 0);
 }
 
-void add_agg_sample(union io_sample_data data, enum fio_ddir ddir, unsigned long long bs,
-					uint8_t priority_bit)
+void add_agg_sample(union io_sample_data data, enum fio_ddir ddir,
+		    unsigned long long bs)
 {
 	struct io_log *iolog;
 
@@ -3061,7 +3063,7 @@ void add_agg_sample(union io_sample_data data, enum fio_ddir ddir, unsigned long
 		return;
 
 	iolog = agg_io_log[ddir];
-	__add_log_sample(iolog, data, ddir, bs, mtime_since_genesis(), 0, priority_bit);
+	__add_log_sample(iolog, data, ddir, bs, mtime_since_genesis(), 0, 0);
 }
 
 void add_sync_clat_sample(struct thread_stat *ts, unsigned long long nsec)
@@ -3083,14 +3085,14 @@ static void add_lat_percentile_sample_noprio(struct thread_stat *ts,
 }
 
 static void add_lat_percentile_sample(struct thread_stat *ts,
-				unsigned long long nsec, enum fio_ddir ddir, uint8_t priority_bit,
-				enum fio_lat lat)
+				unsigned long long nsec, enum fio_ddir ddir,
+				bool high_prio, enum fio_lat lat)
 {
 	unsigned int idx = plat_val_to_idx(nsec);
 
 	add_lat_percentile_sample_noprio(ts, nsec, ddir, lat);
 
-	if (!priority_bit)
+	if (!high_prio)
 		ts->io_u_plat_low_prio[ddir][idx]++;
 	else
 		ts->io_u_plat_high_prio[ddir][idx]++;
@@ -3098,7 +3100,7 @@ static void add_lat_percentile_sample(struct thread_stat *ts,
 
 void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
 		     unsigned long long nsec, unsigned long long bs,
-		     uint64_t offset, uint8_t priority_bit)
+		     uint64_t offset, unsigned int ioprio, bool high_prio)
 {
 	const bool needs_lock = td_async_processing(td);
 	unsigned long elapsed, this_window;
@@ -3111,7 +3113,7 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
 	add_stat_sample(&ts->clat_stat[ddir], nsec);
 
 	if (!ts->lat_percentiles) {
-		if (priority_bit)
+		if (high_prio)
 			add_stat_sample(&ts->clat_high_prio_stat[ddir], nsec);
 		else
 			add_stat_sample(&ts->clat_low_prio_stat[ddir], nsec);
@@ -3119,13 +3121,13 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
 
 	if (td->clat_log)
 		add_log_sample(td, td->clat_log, sample_val(nsec), ddir, bs,
-			       offset, priority_bit);
+			       offset, ioprio);
 
 	if (ts->clat_percentiles) {
 		if (ts->lat_percentiles)
 			add_lat_percentile_sample_noprio(ts, nsec, ddir, FIO_CLAT);
 		else
-			add_lat_percentile_sample(ts, nsec, ddir, priority_bit, FIO_CLAT);
+			add_lat_percentile_sample(ts, nsec, ddir, high_prio, FIO_CLAT);
 	}
 
 	if (iolog && iolog->hist_msec) {
@@ -3154,7 +3156,7 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
 				FIO_IO_U_PLAT_NR * sizeof(uint64_t));
 			flist_add(&dst->list, &hw->list);
 			__add_log_sample(iolog, sample_plat(dst), ddir, bs,
-						elapsed, offset, priority_bit);
+					 elapsed, offset, ioprio);
 
 			/*
 			 * Update the last time we recorded as being now, minus
@@ -3171,8 +3173,8 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
 }
 
 void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
-			unsigned long long nsec, unsigned long long bs, uint64_t offset,
-			uint8_t priority_bit)
+		     unsigned long long nsec, unsigned long long bs,
+		     uint64_t offset, unsigned int ioprio)
 {
 	const bool needs_lock = td_async_processing(td);
 	struct thread_stat *ts = &td->ts;
@@ -3186,8 +3188,8 @@ void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
 	add_stat_sample(&ts->slat_stat[ddir], nsec);
 
 	if (td->slat_log)
-		add_log_sample(td, td->slat_log, sample_val(nsec), ddir, bs, offset,
-			priority_bit);
+		add_log_sample(td, td->slat_log, sample_val(nsec), ddir, bs,
+			       offset, ioprio);
 
 	if (ts->slat_percentiles)
 		add_lat_percentile_sample_noprio(ts, nsec, ddir, FIO_SLAT);
@@ -3198,7 +3200,7 @@ void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
 
 void add_lat_sample(struct thread_data *td, enum fio_ddir ddir,
 		    unsigned long long nsec, unsigned long long bs,
-		    uint64_t offset, uint8_t priority_bit)
+		    uint64_t offset, unsigned int ioprio, bool high_prio)
 {
 	const bool needs_lock = td_async_processing(td);
 	struct thread_stat *ts = &td->ts;
@@ -3213,11 +3215,11 @@ void add_lat_sample(struct thread_data *td, enum fio_ddir ddir,
 
 	if (td->lat_log)
 		add_log_sample(td, td->lat_log, sample_val(nsec), ddir, bs,
-			       offset, priority_bit);
+			       offset, ioprio);
 
 	if (ts->lat_percentiles) {
-		add_lat_percentile_sample(ts, nsec, ddir, priority_bit, FIO_LAT);
-		if (priority_bit)
+		add_lat_percentile_sample(ts, nsec, ddir, high_prio, FIO_LAT);
+		if (high_prio)
 			add_stat_sample(&ts->clat_high_prio_stat[ddir], nsec);
 		else
 			add_stat_sample(&ts->clat_low_prio_stat[ddir], nsec);
@@ -3246,7 +3248,7 @@ void add_bw_sample(struct thread_data *td, struct io_u *io_u,
 
 	if (td->bw_log)
 		add_log_sample(td, td->bw_log, sample_val(rate), io_u->ddir,
-			       bytes, io_u->offset, io_u_is_prio(io_u));
+			       bytes, io_u->offset, io_u->ioprio);
 
 	td->stat_io_bytes[io_u->ddir] = td->this_io_bytes[io_u->ddir];
 
@@ -3300,7 +3302,8 @@ static int __add_samples(struct thread_data *td, struct timespec *parent_tv,
 			if (td->o.min_bs[ddir] == td->o.max_bs[ddir])
 				bs = td->o.min_bs[ddir];
 
-			next = add_log_sample(td, log, sample_val(rate), ddir, bs, 0, 0);
+			next = add_log_sample(td, log, sample_val(rate), ddir,
+					      bs, 0, 0);
 			next_log = min(next_log, next);
 		}
 
@@ -3340,7 +3343,7 @@ void add_iops_sample(struct thread_data *td, struct io_u *io_u,
 
 	if (td->iops_log)
 		add_log_sample(td, td->iops_log, sample_val(1), io_u->ddir,
-			       bytes, io_u->offset, io_u_is_prio(io_u));
+			       bytes, io_u->offset, io_u->ioprio);
 
 	td->stat_io_blocks[io_u->ddir] = td->this_io_blocks[io_u->ddir];
 
diff --git a/stat.h b/stat.h
index d08d4dc0..a06237e7 100644
--- a/stat.h
+++ b/stat.h
@@ -341,13 +341,12 @@ extern void update_rusage_stat(struct thread_data *);
 extern void clear_rusage_stat(struct thread_data *);
 
 extern void add_lat_sample(struct thread_data *, enum fio_ddir, unsigned long long,
-				unsigned long long, uint64_t, uint8_t);
+			   unsigned long long, uint64_t, unsigned int, bool);
 extern void add_clat_sample(struct thread_data *, enum fio_ddir, unsigned long long,
-				unsigned long long, uint64_t, uint8_t);
+			    unsigned long long, uint64_t, unsigned int, bool);
 extern void add_slat_sample(struct thread_data *, enum fio_ddir, unsigned long long,
-				unsigned long long, uint64_t, uint8_t);
-extern void add_agg_sample(union io_sample_data, enum fio_ddir, unsigned long long bs,
-				uint8_t priority_bit);
+				unsigned long long, uint64_t, unsigned int);
+extern void add_agg_sample(union io_sample_data, enum fio_ddir, unsigned long long);
 extern void add_iops_sample(struct thread_data *, struct io_u *,
 				unsigned int);
 extern void add_bw_sample(struct thread_data *, struct io_u *,
diff --git a/thread_options.h b/thread_options.h
index 7133faf6..9990ab9b 100644
--- a/thread_options.h
+++ b/thread_options.h
@@ -374,6 +374,8 @@ struct thread_options {
 	unsigned int ignore_zone_limits;
 	fio_fp64_t zrt;
 	fio_fp64_t zrf;
+
+	unsigned int log_prio;
 };
 
 #define FIO_TOP_STR_MAX		256
@@ -677,6 +679,8 @@ struct thread_options_pack {
 	uint32_t zone_mode;
 	int32_t max_open_zones;
 	uint32_t ignore_zone_limits;
+
+	uint32_t log_prio;
 } __attribute__((packed));
 
 extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 09/11] libaio,io_uring: relax cmdprio_percentage constraints
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (7 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 08/11] libaio,io_uring: introduce cmdprio_bssplit Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 15:20 ` [PATCH v2 10/11] fio: Introduce the log_prio option Niklas Cassel
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

In fio, a job IO priority is controlled with the prioclass and prio
options and these options cannot be used together with the
cmdprio_percentage option.

Allow a user to have async IO priorities default to the job defined
IO priority by removing the mutual exclusion between the options
cmdprio_percentage and prioclass/prio.

With the introduction of the cmdprio_class option, an async IO priority
may be lower than the job default priority, resulting in reversed clat
statistics showed for high and low priority IOs when fio completes.
Solve this by setting an io_u IO_U_F_PRIORITY flag depending on a
comparison between the async IO priority and job default IO priority.

When an async IO is issued without a priority set, Linux kernel will
execute it using the IO priority of the issuing context set with
ioprio_set(). This works fine for libaio, where the context will be
the same as the context that submitted the IO.

However, io_uring can be used with a kernel thread that performs
block device IO submissions (sqthread_poll). Therefore, for io_uring,
an IO sqe ioprio field must be set to the job default priority unless
the IO priority is set according to the job cmdprio_percentage value.

Because of this, IO uring already did set sqe->ioprio even when only
prio/prioclass was used. See commit b7ed2a862dda ("io_uring: set sqe
iopriority, if prio/prioclass is set"). In order to make the code easier
to maintain, handle all I/O priority preparations in the same function.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 backend.c          |  1 +
 engines/cmdprio.h  | 16 ----------------
 engines/io_uring.c | 47 +++++++++++++++++++++++++++++++---------------
 engines/libaio.c   | 18 ++++++++++++++++--
 fio.h              |  5 +++++
 5 files changed, 54 insertions(+), 33 deletions(-)

diff --git a/backend.c b/backend.c
index 808e4362..1bcb035a 100644
--- a/backend.c
+++ b/backend.c
@@ -1760,6 +1760,7 @@ static void *thread_main(void *data)
 			td_verror(td, errno, "ioprio_set");
 			goto err;
 		}
+		td->ioprio = ioprio_value(o->ioprio_class, o->ioprio);
 	}
 
 	if (o->cgroup && cgroup_setup(td, cgroup_list, &cgroup_mnt))
diff --git a/engines/cmdprio.h b/engines/cmdprio.h
index 8acdb0b3..0edc4365 100644
--- a/engines/cmdprio.h
+++ b/engines/cmdprio.h
@@ -129,22 +129,6 @@ static int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
 	/*
 	 * Check for option conflicts
 	 */
-	if (has_cmdprio_percentage &&
-	    (fio_option_is_set(to, ioprio) ||
-	     fio_option_is_set(to, ioprio_class))) {
-		log_err("%s: cmdprio_percentage option and mutually exclusive "
-			"prio or prioclass option is set, exiting\n",
-			to->name);
-		return 1;
-	}
-	if (has_cmdprio_bssplit &&
-	    (fio_option_is_set(to, ioprio) ||
-	     fio_option_is_set(to, ioprio_class))) {
-		log_err("%s: cmdprio_bssplit option and mutually exclusive "
-			"prio or prioclass option is set, exiting\n",
-			to->name);
-		return 1;
-	}
 	if (has_cmdprio_percentage && has_cmdprio_bssplit) {
 		log_err("%s: cmdprio_percentage and cmdprio_bssplit options "
 			"are mutually exclusive\n",
diff --git a/engines/io_uring.c b/engines/io_uring.c
index 57124d22..df2d6c4c 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -65,8 +65,6 @@ struct ioring_data {
 	int queued;
 	int cq_ring_off;
 	unsigned iodepth;
-	bool ioprio_class_set;
-	bool ioprio_set;
 	int prepped;
 
 	struct ioring_mmap mmap[3];
@@ -340,10 +338,6 @@ static int fio_ioring_prep(struct thread_data *td, struct io_u *io_u)
 			sqe->rw_flags |= RWF_UNCACHED;
 		if (o->nowait)
 			sqe->rw_flags |= RWF_NOWAIT;
-		if (ld->ioprio_class_set)
-			sqe->ioprio = td->o.ioprio_class << 13;
-		if (ld->ioprio_set)
-			sqe->ioprio |= td->o.ioprio;
 		sqe->off = io_u->offset;
 	} else if (ddir_sync(io_u->ddir)) {
 		sqe->ioprio = 0;
@@ -458,13 +452,30 @@ static void fio_ioring_prio_prep(struct thread_data *td, struct io_u *io_u)
 	struct cmdprio *cmdprio = &o->cmdprio;
 	enum fio_ddir ddir = io_u->ddir;
 	unsigned int p = fio_cmdprio_percentage(cmdprio, io_u);
+	unsigned int cmdprio_value =
+		ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
-		sqe->ioprio =
-			ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
-		io_u->flags |= IO_U_F_PRIORITY;
+		sqe->ioprio = cmdprio_value;
+		if (!td->ioprio || cmdprio_value < td->ioprio) {
+			/*
+			 * The async IO priority is higher (has a lower value)
+			 * than the priority set by "prio" and "prioclass"
+			 * options.
+			 */
+			io_u->flags |= IO_U_F_PRIORITY;
+		}
 	} else {
-		sqe->ioprio = 0;
+		sqe->ioprio = td->ioprio;
+		if (cmdprio_value && td->ioprio && td->ioprio < cmdprio_value) {
+			/*
+			 * The IO will be executed with the priority set by
+			 * "prio" and "prioclass" options, and this priority
+			 * is higher (has a lower value) than the async IO
+			 * priority.
+			 */
+			io_u->flags |= IO_U_F_PRIORITY;
+		}
 	}
 }
 
@@ -807,6 +818,7 @@ static int fio_ioring_init(struct thread_data *td)
 	struct ioring_options *o = td->eo;
 	struct ioring_data *ld;
 	struct cmdprio *cmdprio = &o->cmdprio;
+	bool has_cmdprio = false;
 	int ret;
 
 	/* sqthread submission requires registered files */
@@ -831,16 +843,21 @@ static int fio_ioring_init(struct thread_data *td)
 
 	td->io_ops_data = ld;
 
-	ret = fio_cmdprio_init(td, cmdprio, &ld->use_cmdprio);
+	ret = fio_cmdprio_init(td, cmdprio, &has_cmdprio);
 	if (ret) {
 		td_verror(td, EINVAL, "fio_ioring_init");
 		return 1;
 	}
 
-	if (fio_option_is_set(&td->o, ioprio_class))
-		ld->ioprio_class_set = true;
-	if (fio_option_is_set(&td->o, ioprio))
-		ld->ioprio_set = true;
+	/*
+	 * Since io_uring can have a submission context (sqthread_poll) that is
+	 * different from the process context, we cannot rely on the the IO
+	 * priority set by ioprio_set() (option prio/prioclass) to be inherited.
+	 * Therefore, we set the sqe->ioprio field when prio/prioclass is used.
+	 */
+	ld->use_cmdprio = has_cmdprio ||
+		fio_option_is_set(&td->o, ioprio_class) ||
+		fio_option_is_set(&td->o, ioprio);
 
 	return 0;
 }
diff --git a/engines/libaio.c b/engines/libaio.c
index 9fba3b12..62c8aed7 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -211,11 +211,25 @@ static void fio_libaio_prio_prep(struct thread_data *td, struct io_u *io_u)
 	struct cmdprio *cmdprio = &o->cmdprio;
 	enum fio_ddir ddir = io_u->ddir;
 	unsigned int p = fio_cmdprio_percentage(cmdprio, io_u);
+	unsigned int cmdprio_value =
+		ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
 
 	if (p && rand_between(&td->prio_state, 0, 99) < p) {
-		io_u->iocb.aio_reqprio =
-			ioprio_value(cmdprio->class[ddir], cmdprio->level[ddir]);
+		io_u->iocb.aio_reqprio = cmdprio_value;
 		io_u->iocb.u.c.flags |= IOCB_FLAG_IOPRIO;
+		if (!td->ioprio || cmdprio_value < td->ioprio) {
+			/*
+			 * The async IO priority is higher (has a lower value)
+			 * than the default context priority.
+			 */
+			io_u->flags |= IO_U_F_PRIORITY;
+		}
+	} else if (td->ioprio && td->ioprio < cmdprio_value) {
+		/*
+		 * The IO will be executed with the default context priority,
+		 * and this priority is higher (has a lower value) than the
+		 * async IO priority.
+		 */
 		io_u->flags |= IO_U_F_PRIORITY;
 	}
 }
diff --git a/fio.h b/fio.h
index 6f6b211b..da1fe085 100644
--- a/fio.h
+++ b/fio.h
@@ -280,6 +280,11 @@ struct thread_data {
 
 	int shm_id;
 
+	/*
+	 * Job default IO priority set with prioclass and prio options.
+	 */
+	unsigned int ioprio;
+
 	/*
 	 * IO engine hooks, contains everything needed to submit an io_u
 	 * to any of the available IO engines.
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 11/11] examples: add examples for cmdprio_* IO priority options
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (9 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 10/11] fio: Introduce the log_prio option Niklas Cassel
@ 2021-09-03 15:20 ` Niklas Cassel
  2021-09-03 16:12 ` [PATCH v2 00/11] Improve io_uring and libaio IO priority support Jens Axboe
  11 siblings, 0 replies; 13+ messages in thread
From: Niklas Cassel @ 2021-09-03 15:20 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Niklas Cassel

From: Damien Le Moal <damien.lemoal@wdc.com>

Add the example scripts cmdprio-percentage.fio and cmdprio-bssplit.fio
to illustrate the use of the cmdprio_percentage, cmdprio_class,
cmdprio and cmdprio_bssplit options. Also add the fiograph output
images for these example scripts.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 examples/cmdprio-bssplit.fio    |  17 +++++++++++++++++
 examples/cmdprio-bssplit.png    | Bin 0 -> 45606 bytes
 examples/cmdprio-percentage.fio |  17 +++++++++++++++++
 examples/cmdprio-percentage.png | Bin 0 -> 46271 bytes
 4 files changed, 34 insertions(+)
 create mode 100644 examples/cmdprio-bssplit.fio
 create mode 100644 examples/cmdprio-bssplit.png
 create mode 100644 examples/cmdprio-percentage.fio
 create mode 100644 examples/cmdprio-percentage.png

diff --git a/examples/cmdprio-bssplit.fio b/examples/cmdprio-bssplit.fio
new file mode 100644
index 00000000..47e9a790
--- /dev/null
+++ b/examples/cmdprio-bssplit.fio
@@ -0,0 +1,17 @@
+; Randomly read/write a block device file at queue depth 16.
+; 40 % of read IOs are 64kB and 60% are 1MB. 100% of writes are 1MB.
+; 100% of the 64kB reads are executed at the highest priority and
+; all other IOs executed without a priority set.
+[global]
+filename=/dev/sda
+direct=1
+write_lat_log=prio-run.log
+log_prio=1
+
+[randrw]
+rw=randrw
+bssplit=64k/40:1024k/60,1024k/100
+ioengine=libaio
+iodepth=16
+cmdprio_bssplit=64k/100:1024k/0,1024k/0
+cmdprio_class=1
diff --git a/examples/cmdprio-bssplit.png b/examples/cmdprio-bssplit.png
new file mode 100644
index 0000000000000000000000000000000000000000..a0bb3ff439595071149575c36913659887a5695e
GIT binary patch
literal 45606
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%0Ag)7s|$_xtk2KHq?E2&x9LK;{+M7+>|P_D&Jd
z&33#qH#uHOJn3}3Idi{*<K#Hy=s2}5+v0mSLyD%N5=6vH-|0f~D6u^J5oQkVmF9B^
zegOZx<OEq+Ss|b|9x!;GK+e$CUTSqc9CAMn{XUk)3S|g@EU3^cfN}w%#`&ZmXb=UK
z?(K~YVKXEoBp_;NDJx@q{^kKN58&cJa{_2kd{5ZW)FkM4e+?o(K)a)(qYwA@;Smuk
z%F3ep%km|8P-c_C`J~NGuyYk3)yjYE$Z<L3R`&lrL4|y^BkJpa@5<ipi!@XG-mNir
zMmtnK#J=<6y-z9&EGgN?;lKq=5Ppq}x~I=(F4%x<*!}HuYziER<~J-A`X~^gpAV-F
zsa)uGtAVqsrRAU7`I=pkAh}dOeF1f#CwE0?&Bn%-$zi($S}-IYt}KEA1N#74co$pE
ziyo&|uD$|VTmhil=nKo-fAi)|hnKJR4*{SkfR>gz^T~J`fb{Nucd`2bzds2{4ud^3
zM5Aigp{*#2V0~L=p$#YWM-d!qPX^~#M>1q0#NLpm&V?4|4~OdTh|nrC#aIjsxSUm%
zSc-vse7`QO;o%{4<qBc7wGL-n=8MI0pIr|PS6UTl)_mvLZikG%^@g0DuAAS`V5M>@
z^r?yIiQ3rQG_CnLs+$0Iesj>a%LR)Bxc|UIy$F~oQ2^#1Rp3$sb2u?^4B~C(WOF?_
z_q=S;bH7I`XlMdZRQZc4H+PFtf%whsty5<OIwTl{VCV3V*JKC{KdQK_tkq_*w!2&C
zY=!4p83xU@V`F2X1--#2yg-IbS-qU`{n-i&_bMO)>HgMQCA^Sax9gR(GytzBaEgKC
z3@9;gzFq%$O9pdx#^g%-0`9Z+Ax?)QSqeEm{_~*N;8|FH417^q-kZsd_U3VM6d%fP
zQ~dhQo{1TX78@D)*QDV3&z52lk>Kv$5GH3zT-<;}Ebx&CBtBonnc}dDM!-77hAL{`
zs+l4NIe}HDRcF?q62!v|9DY<(CH&rh?<u!tI`!~^guy#<S1|@bO#l$wPz46}e9t4&
zOPV7~R&((CQ|kJ!m*d)ZsBd8bz}B@zt?og2Kua}X0(YjffGLS$6OpwIDlis4_ufKq
zapC=D(Oo$g7v*vYXXj6TrN0I1i73w-5I(5S<|$tHcMzcN#Srl}g3h+iDq_C?|3@eY
zE;BTnhfg*xust69b*QL;1=1~OZUMS_MPcFWl<RwgtXdWTQs%2%UHHM}^P)c*NA;w$
zKKIf)^R&J${Y)tMYB0v#h2r0vfyVzE|9{8&3=`nc$eAb{_8W?HG8^e@w5F9@LnorL
zz5L3S9XOlT?Z(}mX`Osl?-uqK7xxx?f=1ehz0MCG3|L25h7&*B_D)Q4ukle8L^D5b
zUAK?$K|H#SJ0c5_<KFqCyg}veeCmJ9ReO(Lo3ko-S!4v2+uC_sq9X`f{34!)gNNfu
z_DMotJ9|>?XHK(VsIOuVJ&D`o7|*8R(1R)CM~XYDn-i}_x(>Fi^9lrCs-ukh7)mK?
zKczVL=<d5|V_pezIW!hj3~oYeKv!~1#m+bo9CN5P?MJ-l#^%nh=IdqY?d&NM-166S
za+NaED$WaECp{FSv(Z4F!zWCCGs1e_xqG)@(-@sEU(R^N_Q%pc>M@gq?8&G}aP>_p
zMyaGqrl7~8(P95V?ZJB5I>8&8U;fx@Tx+!lETgN*#rVYrBV=E<+__JtWoE{`(-hcq
zT6^63aTA!0u$a3%x@=<_|IjPeXOWHh?$>0I#Z$tk!G-Bs58#`F3f}v#O`Ha-t1yTh
z-~cU#<VK(=i%2iXPE1cd3)l4imP7ETuAafeO72Nx)C%Q0N_p~N^I*<Nyd(nG{oh5#
zGclg+Hrr2A{bL(fEhic%Ius@~TH9Jp#&)Ap!z=neIy&zOAnHri_kYKl6fkoJUiYP!
z`7;|WFx!PhMMs54jzkag8l4+wn4=YMF;g0wA!p{5m&#;cvRrQ0T8|zNuC85<zboTX
z8&Zc4D|ddenv(sKo77UcoENP@$vR)$+<X`O4*{X=w54@_PEP@-5cGpD$?!b=_5Lap
zbl60Fv;0PUE;wDZM}{JS(Zwx!S#g{4g^_iH1&nuge0E1?M}1&Dlf;b7%!yC)rr{ow
zqVwCFGj42EY+X-x)6(Pbd95P7tiAT4Ymk803p91Ih@tQD%-e05?!;$;7IYT&L~TjP
za**7cF|LU5rF)0-z)sA}$gIHom6P*TsuEK3!ga}r)z_lZLdrs9ZBxU2QbR@$3HRX6
z>gdhl^h!tzYKOe0!2D;E^O5*h8^p9`>!k6{J5{Au;K#A#oxFH-#Vp?Xm=4o2f&YQ2
zN3oyj3w4;%VD7X4tT^cj;fLdh*sK{{jT1s8_PifNp-ZKJqXvD1X5;A;XJxq)1HHY*
zM+-He4n5clf2#zF$b&uFP$659-}!VA!qXz5dI-#6<MJ6e+6?4w1y1>X%{L++)JW0{
zlB#a6wz|TkOdg-dhTp(bx&I5CKH;_UjqVxUIruk5!t95%4+1B?khg67iT@X4Zy8lp
z*mVsb1rbRJ0YOB%K|nyHC6z|$?i8dOL<J-ch)9>xB^}aAcSwVTbf<KE3-9-SzUS9F
z-ZRb+2Lld!U;B!+=9+V^gzz)vLD!=p1D?X;M=vCmO^^E)^qxHbeEDsx0<ryY(?HU~
zzbdcl-Pd<aI+4sv?R^n$k!}LS{5)#CIn%Qh3#Na&w_epRVX>b@oN*g-pIH4RE><@r
z2~7A-Ke{@8T|`^-UhFKv20{28j`Ci0PD?`RwojFXq#7neCULuQ&r5rSfOyw~w^&!2
zf2(16K9M?y4vL;s7uyyf?;dfWJHsjo<*U3j=GG{~b)$eAzwkUU(<`fMvJDr!=7Eum
zAvYxVYTuf+iRRby0p0Yv=M1v97qcEN>~V;jwT1X{UF|%pV>tbH8-z>L3W@pdw@1K@
zC=ABvM&Tgf3ZOU@${s?GpH7qJ?Q-I^`K8jhJfs+_-~s#L&SrON`(j5<r|OjUG0*A7
z{Ut#zw4Mh8YwAt~%6f7<$t<2lej!g0%dFG!TuL&cm<Ws<jJD5rQB1K0C^DF+zuT~~
z#&(Wvmq>)9Boa8=)0Imtp*!elj-VPi!Y!*1j2EEb`TUcQB(0vT^2=<JWRu`kn>F;F
z?XMRM7-R-!<-gZ3{9^suteu?W`2dO!Z5RG-tlWi^A7e5u895n--%|mx^N4eWGp>SS
zJ=)iK;k`<x<OGP&fP3r(jL96Y{i)<QnCO`VxI8E3UP<Oi8h2F<*{<nt{2aI`yQFs)
zA<Zanw{OQ<z<8Ln)_rH!KP}+lTC99aaz^G2BCQEUOoTGNazbE}4Qp<cY^(*x3;kwI
zHO@@4XT1ltqrB~ozwUMR3Smv$zuKTIBnaLQw)0E9lryi#5kLE<({tDE(r){RgCNpk
zzo4H_{*Z@m=;ArOW7g249bCmT?pj)v_XNSv$-vynfa&luW>;ci>5p*5g5#_UO={@Q
z>oGCI&o>Y_X!iw3JqJ(a2H3Z>I4Y=0s43Vy7z#^yHEe6%)_gYk>_v34%)H`2zOS&G
z`Rv#F-}MhV20^b*?o4fu6>Mkd9n31%^y10O$Q&T|bUa)(%;)+~>nD3-r{w?7zPjgg
zu*uI7Wc3PhRQ-3#V@vrnoy4^}MZQ!I41LuRR@VKw{o-<jMo;?`B#fl4Ng$sSybO9I
zdLxaoR(eav-R$txsOvjhA&d0Tp2zO*06vF<1Q*jg)BFw{>N*WalOpe*eCDP?=R8+r
zx&Bn@3&9eRLV<iM&SCEado%Su&0hP;_JFmlwWgtF6c=kWGkYdbUN^!b3+|14NUxFk
z95s`D3-NgMi7v7>sFq}7bM1n8mR&<g;}XlK<~q-pJ<D|!I`<4ge~;~(`M1(<b?bC5
zGA;fR_=R#B)D`yVGe^^9c1F5}sIw>{%R2idk#b9}$|E%dVndANCU;5{MW&F@eS6RB
zU&?ASYG_rxm-EPh?rWrV(c!ucA7pppxm2Scdh_1?ierLAe=93IA54#e2o%pT&z~{8
zD6L{A_wA9KY>}Mwm!=}(C6c-$e$Kw_6FU?uOm-=-uAw<j!K}xZucV^xl=TAj`ZdH8
zcYYyf@3YZkj$FFnl!pE9Yly;$?LGd#6xiM@HY|0Qo8B%yhshZ}pA;^-bJ}w(vm2KF
z_KmWXlTJ_ks-VN5bM-s=<%&4!V9YPA@T9(I8H+Z95v$jC^Gy;_@U~2_!Rgzs4OzyQ
zv<#X~D5`qDQ|*iH#9)PrXzT8tEHVlJv370kxpC{RA0ydl=^n#Qe_8a1_DHqmb4z(=
z7QL8aUpYHp4c}1r&?6b+Fq$y`P_(n@u&lGJWBa|8mE{$5NBc8-PEStVcHO#_I(1#?
zb9h!S0%{*vty+_oFRF!FC9v}+`}xwcuv-`W(LF1Q@<`!7JH(~OMCttDQ%F(cp*XEu
z@31LP=T3M1_O|`?+w!dZ&D{-Ntect+YI_o$!ADhIcobCVs0~k#{YEK~-Ej;tXLuI@
zE^&t~V`N1ON~BLnH)$rXy`g=sSC&MKWUUsj{9fx+qFC~{dX_~(^^rI4P4gq&x~2d9
z<PZqZn}cK;EKDLu#N6FaAhoW5(A#cKvgS1t>cJ}pE0*A%V4GEv3yR&HxjRcvr~4Z|
z>ld-KLRQaj@Q@dA7Hhhzv&9$5eiVC{OUGRPI7;M!b^pZM#L12N_~=MAt*2U_q>3x*
zdFvk4)l}Z|iIDg=F7)lx&!oQW$?t7a9~i8~VD0BEFt>8sKXkB;FWE>Qxy*a5XYizv
zFxg2|L24^&>4Q%5kNifV_d^vUTb!fZ=Fi<<{}k2b(Or^WVhyX%*7HhC3?xTTVNwlA
z4DJM$KH_2i$y#K&$W-qr%&frdaK}N?y=7^v*J{F&n3;{vhxF0w+LpfGitBPVnku9S
zRAaQ70#95-XJj-pIz!*+ZrOJ$8{5h6>fh5`)AE~iDRJ+tS-}Kio$fsJbZA+{H?Q$+
zixJbHM*Il5%axLn0>LyLhyUW@;_~t`K>88H@_s++u-6<%R@#<jH}`5jwR~ExSzhch
z-EGLeJ?c20wRV)VtRiBHaQ^Tu^Mk@`9;Ju3Ix#VOZndn*yp}mLIUr^=15otIebxJG
z8pA>sLNKY++mANxm5jW$ePy+gIw&<t6^{7P(sqzJmQ0#LnrbtkG!h=~cWS=fk9}$L
zT5oM?Vme+a(N2HLSLxA0>0oyLw@sD)To1;>LVWUDiCoM*A4l$f*PRQlAwEjHi8wQ(
z6{Tg#{gS@$D=Zz+_iM=hxZ5NsOR|)Q<_4+l)s4G&IJC^;o9Dd?;rq;e9r4=UUcP(D
z?FCPvh14en<xjSM<Fi7OVdZ?L?Pjj+HJ`q>!Z)#G?W6LSse&gO8Q85p72~-T)tSpS
zQZ_^zNgv4_S;SG)zT4gtnG}pWmFZ2?*!5%GWR3gfDIuA{i+jK+jV<xZkx-RWm9lMp
zJcWsPa(yz{)MtEcyfwP1V!t%dE|B%3){n*xu?6b#xbppt{Se0x*IUjqWld$<pN2|Q
zF&)q|U#2w?wU#?qe3DKxnC`)~CPJv+)eszZqlu(XS4qbU6z9g{_G0u3(h`LEkp5gI
z-R)+q+SeZiA|9Q=kwn4vfjFd0k!6&vtBZZRwSD#uan*6L%du^|7Z+$YJu%wXkxm~u
zq#lH4A#?7|qo6i`laXW*Zx{Gk0niW^9}nD20CNDc+6SpW(9c=b3lRko(a}pQE3rvQ
zQzIjpX=(Gz%UNG{RxV>{X=v^VdAdUIPDe)vRf^}bvc?7m;PFvWQPJ8;JTTREcDz>r
zwM1~SqoZ@4Ye9+z;4UsLfl~r6;Gp&OdKwyTfO&Ux=+!i)+$JYK2cNW*6e_T!0FxyE
zvH>S~@fYlej(UYJL5+~~?p-6OOL}^6FsC{@*Wkm!f&$8Z;ZYZVM^*sMdxs_|Bh@%X
zt9cv!Jy?YdeCL%lvt5EsF~uSEnMhpbW81@q$!IDzKjZhP>$hf17g};97R66!P6>yI
zIeu}iO0TV}7mCHKz1Ze8vJrAUof%%#sy(k&OUa)fS;Ta>H9<DY{xahpftU<+Vr?S)
z%;M0zhK1(2`Ptl;#+#{oDP9p?n5!70F{7pFr7kR^KU;fliY?P02+Mkse8N*6P;PAP
zF-x&7w%DX2k|YZ9)~ePlkkVtfV8ENhb9iL`Ncmv{(>+hmJ}8@i|Em5%nV_07?o(X;
zn$Ar$Nh7$i^sk^oL_>h+$Rbbpb6i|pc{vXgR6^&$BuAqzK{Jt&A>(1oPSISEMC(0A
zaytGfMuY0!gWpxZmnl-|`9EfxYum~@sFn0cB<{zpU8*0nx|Rx0^(7}{zloY|g!016
z9_5%XW=PQQfG^r;FSy6SSMW^y5E`1Fds>q{0){T2iJKT12~exHUkCz@DOBPR;F|`V
z)80h>LwJAyqo|Vu=LuZXK<*Tlg{Px4d1XsiT#SF^C#YZe=N)AIWA#45Q$2tSv1xzb
zUhF3GI{&GsL@waE4NvvRKwp0b6nKynn(FJnIm}H>EdiSmC~@V5R#do%i2Q(Qi;nvA
z*|YX5EfrL`;6-9<rmtV>_-I{+)S)}E8?%Q^npLJ5CpklCUw$`=_;XlK@aD!=Ge#gy
z%DaHZ$?w%inMoN!wS;af&A!Cr%Hs${bv2Si;&YabF^)^4QO-)l%$==$^V3xBCsvY!
z9~6pv+kZrij_X(&T0Yc2(ibk8o@%_%Jrk@UPc}}j7rU@=d_|Lt_+YhV!|TNDm3T?Y
z?)Ld;*?xXu``w?X2~S<?r=CsGCnv41to>Ydt=TzhJxCU$^FTZ(6Da%sl>{*rT}y8p
zOZAYHKgB!xwlUU<^s;(yand?NMwVSIU;9G4BWl&FlZlq>^Bw<-dCv$sDl1R$QOV4t
zCnKBq`R?Za-@jnS$PSeuDBSNpDJm+03f<z&3_xg^AUNUT0&VB+m8uaeZ(jd->Zw0n
z>9907I0$xNP0h`KFJ7GO^<Js=z~&KD`UjG1x;0s8X^yi^w}7C1KS@+~p~myr9{BQz
zLZ}kLV%yu<F)=fPDt&cXnNuI;-@`*N{1E^K0zhSpy~)$Rf3N@f1CDEDkOG2>AyJfq
zLLi$?6}W{st`0InNgmj8@ci99JlM6$vEr{ac6Zm>P78tc<?h(S)U^*MI;6PuC+BgR
zQB3XhZmwene4>@VSGA*W69@fWmTilzwsToPUGUc4P7TU>?xJ@XoJVZKVdHG$tdUu~
zJ%S<S85WZpKhahGM}HAr7Q1GDb-2L0e)jk_5_xuiyLwEvq^!!S*{$iO*QLkF@ruXJ
zAuL;G*5B#$sZt73$=aVh1y4>C2{gk_DBx*oetfb0VFmAwQsk`v>?P)T{okO!iMssf
z&c}a-<WZ9zCR$kLnsqj`;eW!LJ?Pl@k%}VoGP>(_tes7FrA&DAZ@p^0;@bD!{(lU}
z=6mlW$(8D5&^i6fd&h*vC}nl#+#TTLmXA-0n!Q^vJu!!U-hNCcCqC>7-c6v@+5Q8X
zk|KP5etv9hWI{r(R)`*WK}yr0-Mnek+x5@b73^`q6%O~lz+?Bn460dKStP{70qIh(
zlY;0nQ$8^$EUa~xl9UXdhn%#uz7d)IGfeRG!3Xi*>dAnD@Slx)fFzfcIP{$W2djyV
zK;h`BV(Gdw3#CH<HP2qvefZD@^+Qm?7NH?SLZH5HGg$>RWg<`!uV-iG<*`KihCFf>
zKW9T$3K>qr0!v^?u&Zwg-1~s?V^^cIo4d;_@kroBj5t*yE<bw%>nBHnz-S~fbLnvT
zqRHGj|IyY_gDc9hg5FpQADQi|I=}N8Wut|FINW}>{<3dnu!c%`4YMs)Y8~2m3&rtw
zl$&TFM2Z%!AB^m8p5QZdfA5*7wTtQKv(eMgwtLcMMQcEt_d2oX$-?yK<QgB?ec#nn
z@T&2)I#jD@=89KJBqlv^YjJ;~#cw5T*@n?}{Y}(oqKk3&L2{)^88IF1r>VYTWw(u$
zm!+5CE$d8(zUvp*MmjJs0Ip0spYaeeF)?5j=zV$aQZo;S6&4nj`mI3m21%`hgM;e`
zH~UJENS_6gBD#_U$$*_r3cCmri5&^Q2?rvSW3QMlx=;n~{rQu_{2b(8JUr!4BA%f|
zy>4)NumR^9c$K<xRyc2HvY0fnXn$8!Rpnu2MLwtb&+2gSbMo7m+{i6cGh(EcRFdvj
z{P~cR9-p5jhdsyY8^JuGwu2Y8{xr@<#FzXs9E5$2{r3A_`RULayH^$)5Zw8fqfyFJ
zj+2c&av|7%LpDJcoyGR^g(Md7+Kkm>;^8~xP8G4;j~co75Hm|N6|t`z1W(*G-Nx~U
z6guDWk@9`=>FaOnU&(%<$@fi<W8-Sn9v%2$-RLBx=f^-5g~NubxTU8@9&D_Fo`TKS
zZX<XF0UH90uY4)CmX8E(g@<hgw`0IeLi7PIBt?>jh6YXb3wlg+baayU$DLR2fYvy>
zu#g^O^VV;CXvi-b%ag39wH3^GpBk~3y8N4JJxTH;>t4(kk8dN!t0u1Ql#R-x&^9w*
zo%zCE2%}t+rQ8Q?11Y_&d>X{>!GBHUjZs_nTf!>$YBV(eXnivdLf&h+Z=86`udW~c
z?E`d9dDvPB2?(I}Vr6Yj(`yPs-?lXnZ8^KR+(bje=^8@4VWGnx)FSDhD96Icc;zyn
zuFgPDFC|lNXlMx36|ifXolT}Fr=_Da%-qHglCgR9s=K?pnOPsmxxeI%qzGg~q_7ZE
zk#*GUG@m|XFJvEmeH`}KSEMhp-$`SGv+#z5frRFhlv=!1J&s}dr%F$4eb}i5sUzb^
zlx&m`(rnM@K7E+)d_qG+-{2D+_KfivrO#=?%Y^q%hm1@li_96d)TpAjQDa>Rii-O`
z(aONy0E#I8UOMm{4UCQ^b|VLYQ)nm-@I|0fJ$GqtVUeDhdH5G{)BYGR4g;S_s3uKT
z{r;`M-whNkFqOjE=W&Aq9}Rx{)D%3z`^+GAfMWJf`9DKR0&Z^=Xu!-9P67`tt%+ah
zGDZ07`!1rQ*CKzIubaQUWshMgZJG8t<MB;Cf@k80W$FX+J>e+5_^^>bOEY?3N*|=t
z&=%13icI}*_2)Q9epK&hZpwh%QfW=YL(CX0#b-V)_>!-`miP_1fmAopa+yf(y=<DL
zaP@^#n{SA({^;VZ+%5WW>8rrb#4qr5u(`CiZu#Ngy#e(MbObFn?diqjO@xff<!O+{
zW5ky)Hf;ql2cfrNjEraHno3&40&pfP9a=%$2Z;~>ll%Mo&CSi=IR=MaBL&8N0auuw
zm%xy(u$@+Y`Eq`75!6vk%*<<BTevtl8B;<wvZO!9-Tp2sDJy>hqb%48!Qm8Uyo`*D
zy87sseV;2opTn(yfB>0i&ls7RD@scViHJT)(@06R#&Vg>4n5-LCck$tltP$|i7AM?
z?dMP5-hTKnLnEVVhb4J?d(MNWmvG{yu9?rC8yp8Tn*^s`Na-}{q#vgTuLcV_dnV8d
zG1pR&>$NRXO!$Oohd8@#Jf8QGmRAh*^G*N$^?OD-8bUr#K(v#qzQ__4p*>PbT1hgA
ztUi6bQdILrK#<%^-br3TuNSX``W+j-N6TW@FHD(U|D@XUlk%D`o)$)o!z-~vW^MF+
z(%a9MFVhPc^4hw7gm7muW>?C)kUOi&C}SevkA5e0ibMutYZcfzl2gKJYHN!BV1@)a
zq<Y=x@Ng8+#FUhFpcZN*gAMVBq0{5Xk73P#Y65IhTR@o!aop^zp^eQZ1dPwXuD2z$
z<!Tbl&bkBdDKQb)6*{7#qOc-8JWiqdwmsCq2-^uLW?9q=;q=-AMhtl7!Uxr#?RElJ
zsV(=_c<Bn%{lJqBge#U77D_K)dV*JaT@@WXz~j9oFpU8jKiKc3rry-J8`%;{H}xDD
z>2hytyJ&Bye3*`i9{*XBht^i$UJwf6=3XYFI9Ib-o#2V{aoz%KzS$<(w!u@wrGpF@
zj8%Eg28Q}6MX4MXsEE?EQeAR4lPvwwp@~S1*jUx1mWDQa&t^OKhM9L7#MvzFRfpMc
zKRz|`Ffz0=l#@Y{gvE>y6(Akz)#+AdPlBW3qAG_fEfy>Uy##|_65Y5Y47tgpV3$<u
z>t*X>3%}y1`>44?oO%@<mbxh2RMQ4F3IYyi_420HRx<;GoxdvsFqEFmgt7_>3g8Xx
z;ZY54a$xUFKABll4s;<_Ryk2oUr#p7t8hVDsK+)9i4d`}vI0L@@QH2??F9ugA0OY}
zzhGDwBqsNT4j8k@S7Rw)S|t?BM?=%p)wK@R@-VS&EiHjfW@Kgt7V+ed&v4d?YHJh4
zsenp=duLRU9J$PfZ6)r}h!9cGQ;;-4Lu3Wz;6D?u)LVemHu!=qC2RQiSb|=>0u7$Y
zkqIiFa2PLZ9y7};mZ9+ep9FF>ifWS4iLqXTaCsU=8lpPB8EJIQ?<3=);!;kiY*cM-
zP~OnIud+C@XrxunKoRmu=D%EkV1@`EFW4St@n?584_zRYx+8Zd9XoxtW>(qr9gEY;
z2~90Ut-i^T?#7l>#%#Wq`eIIxQmP*@l=5Q1+;uUm+Qgn)S+OuQ1i<7v0-Sxo3K$4m
zi5x~~5*_FWIJw}2LeT=Ba<cCq|9tVIeue5kwHf>FotTsvYNtsc%*_uU6bpbxnVOl&
zJE#$KKLEozD^$`kx@Fj}5L0XERWpyd#ftUVxxR~>On2xFezf6v(}g5fK@a`PgfGC&
zTKJnPiYYaYj#WEZ@-X^g9Xb^&;d^jXCd?YaTf(E)d;j6>?abT9x4XVxC(B92o20$k
z`R|GmeC9qmI(q!%$#WSQP%aY@5<-f0{Rf4QY-cTZxac|2_5{0ky}rV_(4gn?^2&_<
z;$uU1<Knreb(kD}93yl2Tgml$3d*<$3^I(cfO~r1!0sh)D1v-^v@N$YxGOA#9l5o#
z##g-k!Jj0K)bBwXP0W`(z~nfXnZYC-eZm-))e#s7woHAdoc0%!!L9VKHdQe-2w25m
z<>j4hauyT)xT89v8?6}CH@agX>FJ^1@l>M$5SY0UBO9Ik0nE%YQmb#Knn*o%5*ggi
zt~lAV!pdB?8V_-}y+KqH<nZt?_;p_Gwam<Ov$M*osx7Ug-ncMZ;aL$9`n#3zeM>BT
z?DqT2)y~UK$0`xl*CXMD(Ra2J2geg~W^p*DyQHxs0DvBDYz8}oSwGnNQ0iPk_nDTY
zgEUl+`1|;Qro^>oiJ)M6O9x$|nuIs^@lZw4xb3XmZlj|@`+#uywj&<duC|6}ts<==
zorU$b_@o+-(+jzZ)?`)`oC%HSeh7(t5JN}E*FEMND|&#wt0TtzgA$PQ_w)Ym=iiq)
zRxn^N*bI-!+C>>^8(Es<$b9akOO&hnRCTDlX`*U|VTYc`BZ!T#qqU=~q%@H;!E(eZ
z5jP#P9K$H|DH<|vZ^ggFx=a|qM-|A>%3dMqg%qeiiwL2wAh1Ds<C1e2pTeu&eN$L~
zBr~{KSrP)WX930VB_o!)H|!|m)KIvUum!&6k7z6C`oa}Bs5v~<cv}^7l3n<s>{S`!
z3sc^68oV$8;o0OrVLnWp!n^XjiTrC@S+{ZxXyFpi@eZVfvndK@!k2ek=jMW<g4V~a
z5e&9$?6z!~_cvO6c$KHA5&|NZa`sim*(u<(E&h^+C;D-PhJn6~cQQIMd`M|TNlZ4i
zD0RnXcT&sN7W-7RS6o3uXv|CU6ktq9iELV?|MqT2&xfChuHAI=K2Eww8fh+|sP%Dt
zur1Oyd>arpfYRj+<PrM$hBhp=UEK{jeTp-Qi<85Xrs<~5?Okq6>w~07ZdJ?1F8^l?
zGGCIol?5hY62%rP4u5#i<~W<UijByR$`2+aGN2{0Bx1HHV6aTnR!Dk#JK*EAsj#Y~
zD&j%7bZ8j)4L;Q5QQ<$Pe_EJW;)_B6xpe=%e;Bz{)?6ltFDOm(Yp1z&!)d(;1M?2i
zljSFlhb|=?#n~9S*WaL4G!>#S)LPeO*=C5G%E!RL7=ih(1VLZvR4I@r;Ci*0{FNoj
zAtKh(OS=#qxSOF4-&*KiK$0Uptvx-G*KZ*31I4f7BlN8f2?vSIgRL^v(z&=E+74bA
zvP-!?ap!qbj&~!3l`;?}8a9dCFmzE6hREf0mzZeA7w|WS?Eq4kHg!vLa}f9@tTRX!
z<Q4=6_yweV42Uc?exSsrbhdPm<cxrjErd0cyc83$yt%b#`X?ik%+tz#{Hq<5Ogy>z
zN+jRMh1<LceK05YK`bllYgTqipuh{+0(lB0YN`Y()a#-;FV72i{`i`i92p}-KFd6+
zrmN1&mi=V*k(J_>2x9!=?U(<2lw<_AZng8Pjqx(0`xu-<0NH`=NBjG0gJKlXmS2w3
z5f(}7HD@PhdT+gth4(J!^cN9tW)f!JbiKjjZfNXCrO%Fj8TE2dz0`f!($m<$&EdH5
z5Z6qm3++vFP;iM=@!^eielu_RP(2*P2b$TEJhSI-pLaa%unw_CD2~5;Vy$PcP5t)4
zG}hmLlhQc%LbcwpejE1>S~T|j(E=$yDYF)nil0h}WwGR7ParM*@T8WD!2EZIv=YJs
zLIUy^5;78A9)gH<?%$mvt%VXUoqOv`D=I4)6|%J7X}@b!29pLuMzWb#kAf&ZE6xka
z^Iq}3J9KxHZ13x^)!B(1Qq8EKj?En#(M%D1?FVhgg8OeL#E-*CNtm1@)BWY%Fy1Kd
z`QC4hPpJ?pt}k!2W%Xpe%5~~<`Vv#}6cf<zX}P+V-4;M1$GFF`Rk8t4=B(iiK;jzV
zUOtZDyMM9W_q6*h;{C6TUw?D{_DspkaLe4Gyo1m;(C4$X{~YVfSHQ;pm4)&vi@`ek
zzVHp~8|uWPh7m9&M=9&Jc&?&1kzP_f)L7HO_d{<h(1;%qmhP86+mqfa+#M_%nyjcU
zVA!^Z!fh5BTuoVpZB%AYc@xRj%I;#-{cU)2_){3IIKI+bt+!#wu$t=>WYfoyOA7Hx
zY+3AIGE<}fMEum1HL@<VW;N3!8YFf+a0*>RpV2|99=62dWI(Uig&ix<_ur01>*not
zW+sXw3h%Rzh7^`iWMIl=vgdT@A&h;NPR%1(u8~qA>28VDzSkL{#{ySwENYtt`!$3{
zAO9d_hDpfCJizOCc6N5h{LD&r?1%Xyr`gN3f{LW1yAkBg4>GLvAH{9%P{YccF5KxL
zO-xA0cxo?Z(1FIIC@b659zic7Q?EW^wAyqzqPLTj6#IXE2_^B#9hXBkldJ&-Z}@BT
z9$aj5;LwUC4_rTLYOec8A0!kQM1YbC5g6EmMSc3zfSD<O2K@u@2#k`~8PGUPP{@`C
zv(=4^+U4R0+b}bg&aUF-L(`gKNfeZKJLbpCa{swpVRy&2${P_@9cYrNEBA#VRo%rV
zi_YWV;W>c31u%zsg=TQ}X=rS;va~!pIs!9cpkOfy0i^#I;ugTwfwl>_It0CQnebC!
z`CALw1?V<_gbt`YfbCkEn!7tYN{;}az$Yh{qY7W_j?c`^Jq4{AG*kh(VGI)a3Q$&F
z8QSu%ij}%GdeGA1&6_t@_9h%0@B#Oe6!_C70p922#7F#|oP@~dnh1pUQ&Zk)yio_3
z_p<9R+?nZGY-}$<a;8VYL6!1|I<>AoIV-QL-ZA?TD3+4*=jY?TfA5Hjx^HKP!^NdR
zNy&3olBv+j%)IwauOJ~};AmFD&c)^Occr1E<SZd;Y59SGm!_ifFDlBP7AEO^(+c)Z
za>D}z8g<&BllY%&-SwWXFYr1p&Z|!brE7k{r3J<OuU|wihgekMFV#mqcjq&`K5lFb
z85@6>ax{{1^o7TOz8l%XY~=_E7!OZNL_DC*Nqi0&^_K&td4SPC<pS&|OpMP;Bcs3_
z4_b3T&bTcJW45%kME~Fc0`ce1A82s{G$yIgd!V%b$+W$<CnYWpmV^2M;#78E`UlPz
zu9$$-+E`gZs@DUE_jX>mz(dVAa-MQgrFz{wJ#Ox@WUx<2OGC}22I<V!mhDwn4wtPd
zWKhs`1THS_`Z|y>3-j#6d81k|@A=hV1da6L{fvmu%kx*sO`2cuYGVEn>>%K6ZJ__a
zpL}@Gadb>DIOI$~HUf#<*<Fyp!AbtbPoJqSBjfk!Q<R<$@~2weM3qxi`~>G2^|NO~
z%xWiUYM`V`Nm=K$VR5n#nyl3dX0bZEM}q8D4tu3ISU|kR%lfTn?3h*8tPxEG7xx7k
zTGg*#s_>Zz1}4iEZv?`~=-J)7n|PDzr0ln^7G+D5c;1NXLdP95GqdZy`ZhNCDJja@
z+GjA)zzzT!{XFL9M}gKnKcZN*NJvOj^VGklr2LwkBqt&|0ErL~PyuVcXKMzU34q-I
zmRy>dLBDmYy#pEpm|elxg(YAp41){tAoN<Yx3`Dp7Vxm3R&q~(j&m?RoueF2husuv
z84$$7??c9P3m3PyqeHXIQU&^T2n%0k$i;sUH+=c>GgLTu^6mPH{-K-K>vg51wssfl
zXlYrMm9<Sxi)Cg1{`o^YHio^p=p7r21H*KFPUGNEpO$6`_iWN>?CPe0fe{C0niV$K
zDoTHnxt0b9z8@WRWGY~Gb<GbB9x*eG*VH=LPCnPG*EQ*<Vnmp~+9)dZRMwfyPiv}n
z%$9|P@~G5xZMe^%F?EUsS%h46FS0BuioAC17%l)B;h30w^Y(T-+%#ci+P%0q)n;Vu
zA)v<s*f%o#PfIIzN84*;KJ_Z`hX*jJjZ6TStG@&l1{j8`ebe-dtnoT^o~m&pX4e()
zK7)}zg_bR2qoa_SL$?;B3WPsAJUjs7K{j~A3_kG3g@q4cR1vS8omJJ;eD)UQAj=>o
z2Df1FunY}l6A<`4I!cmD0jfR|6K-qQ{|>h*0~6E9>JW2YG+;<zBo8>Mo4fl}lmh<c
zpy~Th!<Ny3*8WL#O}6bdLD!Ejlz$oOKRB3eCUtg}L@aO6j*koN?RSG8=Xv%Ef4FCu
zpylNqy1LBEE4M~7KYhws>hYRcjRWZbpQ^If#Gfr&6N~IO<ZN1WC2kI{6%{F?&d*M5
z<-x@{JKI|14H&BnA{-t6vT4lfXibO;3aobjBANJ*Pn@f&Hu7i1qTFpSGYz~mnW$5J
z*tMmfxWCkU9<(<946K6Z=I6gFB;B+B!gK}ai~LKxnCFtX0X~b0jwT}|osGptEU&E<
zXp}5Mfd-iK7#J7;4?>yk=f4*X{;i4lU;yH-@ZjyP^|o+o^;MLstP)O&p6>2%IXQ4(
zF)=b`=jCaG^e73;V_}qFUV{{DA3gh#mWqmmk#(uwR*l=<w)ajA(%1J7P|4v*fz2Wx
zbh(N7t-c%TUnQdXgjChq`Uc`L-(5qvsE3@t`1pHa7(Mnft|J;6We{)Py=#Z{>x}Y@
z2A;NnKo<<FE5D{@gDYInsLWDF2haLLwtReq_oWwG6z6pW8QENsk%Ma9cIy56`=%Bl
zuf#`!m0r#_zmP=qjS!a=D{t?#cXn7Rs!?3vJqB#}e~k~Y+wnlIHP6rimXOz=Z%$Eu
zJ`MuL#`|=m!j}TPMO%CTDWVZ>{`vD70vIl?>?nG39c^t`@!ZN5Q3s>18+F-rshF8%
zbg%I@3CUxQ^QYMR8qLnNvLQZ3%u%v`hJS9u=VBsOSD#$_(anl<=l}F6L9gX_Wrfs@
zos;wTyb}YCR6i`FaIyn;j^g6aMFzB^t*wRs{}TCKA_)K<f`Nr4je(s36tqG@LV0g<
za#rKGt<b!+!8Pze7mdy5JQC9|jH=wAfS8?;i75`4%*T`$cH>5=>8U#{ot@VaetvTH
z_Q`voo~FaUb#$b@jZy7vfq|hcFKcR)y07qHSlZ5xODGAK|Ey|MieRE}B$$yYB?O!K
zr;xmdb))lN^3}~XXRig)1On|L%^`(#1^yUSMZLn+o*c-L4(@KCy!o5sxGQGN04bu!
z+2QYsYT;#}NnrCxB~et?tQN0e4Fs-7SM3C2h<-FcdJHpwHjI*T2hJ!c>cD}W_mGjX
zy|pzUGExQLw!}mo&?M#LbhNaXE_U^ns6M0l1#@w`|NY=I@L>%M^a}`RZEBk7oD~4N
z?&wYA;Irq?Lmyq;f5FP^Y_a{qbBJ@UCjBY6=Un^Iw>_ZGO+-X=v>W~>i=WgM4Q=-R
z{k!t=MQCV-*47~~Rit3Y;YN^<2BG{&kx<^;T=DX1n)XSSk&^l$tgbVut2+GLh}~f+
z$j#j}L5TcvKJX4TH95l3X+OMI@qVIG6VLj-p^)d1>ykX(@%I*bg<Ut-7!{S{B77nu
zv|TCx)XimnN5PA#39X7hYm|+FU19Tve}07z9?PFd+@5EaYqE~f^FF@n*arI<kYND*
zg#o&_xPWN~XZBB1Yv7W%KvNR{wxR8UhDNNPUpioDl$2iqG=nA$P#%xc#Q`?}05#b)
zOF`=K96V9Mn*n@4pkG8;Ss4ThN4>ZPghkjMwK0GjLv_Hx!NJsY5uhRPj)q=z9v&X+
zc~Bum+=KEr6xg9L#;7|Iz}}j%F~(#e^1~A+znq+#LPNaFxxUfS3#}B~*Yr2W@8;*X
z^V(+k`4h2g(y+309qbs5fG32JVaMg6Fu9Hno~C<InTn9ztem3apFE8undpwchXi6z
zgT}|*ugx&mP4)j9J=7ax>l^PV1Uq8+UVJGn9qMI=_8qP>Z*Wi=GhYeZA#?@Hv&ruq
z(yCGMp`mZSjXVwttrPo0(ZCnW=f!i}w%h&-ZyBK<wVZdRw@c5TZvo`FIu_ST5u0m*
zz8TX+1GRdnqIFZ^#z=^A*x1>HJr34EZvm<bj7wJLqgDzZ{X2lyZcf+NLrl|m^-{3P
z?(6T5jg94a*hl&Y!m8qu63~5nd3qLp(y4ZaR!qmIr#^BR+(D!MwYpsZjN_6&aRdXm
z_1jtn;mMZ+?-)QtsiHCjp9|4IgU=dwXg;jRmKGAiQc^9|?UVhNd5W?jb31d9qZ7su
ztbF-06dFpYkWBQwI&+SKka($YfXvt;UewN>Q_#)O#NbbI{6tLr1UiC>YJI8auI+D<
z_X<RJ{r)rku&|mwM;>cy<G+0uT=<E?Taj}5WZ}m(@|yuO9*4z+V%D`SN{)ZYf&TYt
zE;?c<I(c0rqr&CR7G#)mgtB!J-gv0T?gXW{Wq@CYlJjq~$`Y|@OLLq8U_RW@!30*b
zyu8uUG_V1JtmtNPOOfl2A*?C9aQ6FW`hGCUMkxga&!GV6vN3*#oE#egVZOV&JM?k8
zef##0sRJCWkSNmt<SRwkHW3Vrj3y=~H_*^vhy4&79I*wcF<A6MIj0u{uTTQn+-xzt
zzk*EPxh~~vSZ%DLa?vFVQkqX8Atx8!ze4VMW@K>Ado-e>7owr%ceGo0?&s9x=f6<=
zr~)d4DS=zoMPx9b5PW=&tS1Q$yfeGya7{!{?{8zkH(%dlh*R+K6QZIpdXw(_h#nAa
zLrE>tSS`Y~99?TZJ3l-tvoaHxiY5r85fifu8lr%<Yy-nY-p9p%=UQ#3!r#N}OCgh)
zyWuS(ACP<?yNmiJqleC~{tn`YYUe?ii4PY4$8d3~<FsP|d5;9G_z8v8=!FQKg361V
z-zW-+@c`Nc94CzRNd|4c6Wyw;yVDacls%v(wi1!g8JwS0a2B!bOdnp>6}ajRX*U0C
z`bwK$X4DfphMz2%GlR@R&rS&Di+&N`*xgVo>e1L!$$xFeW>=@cxFBc|<JSE^ls%jn
z#`u1ci6hu((&+oxKWe=pFLx|U2;-xOBOd=Xl)~`k@p57sz9j%{lU~)`PvU*F&YFM!
z?EBp}c~Ona`uP3i%^>g7K-fGd59Rh)t=Oo;rGM4@0$d6RV*nwPN=cl10Fs7<Cw=6P
z|H%7|i0j|we(1Z>%J`+=s*9nJ*aCDU1Y-<nN*S3v{V=#hwh(qWsAnxeZ6q%4#fc!b
zugGY<&n0j{==eV>6c>}GrB`m#2SX1*Ny*E_MV^cdn+!YF_`v?5q1KL7ON(si|GC}i
zCof=a84aBl)yiRU4Gc@Z@}jtL<5(uzGK!s|ll#qf9v-hboMzHg;W&c)gdgvU^p8J5
zI{Cz%-@2srgd3pbqZB+BbiJYTY|_W)i1@TJ|C`O`LM0(<AHnk0*yKRuU^AJ<*J3If
z`n2T1uo1rUWpy2o$?l_g*IVSiY(FSPB&7YKM$x$Ex<b4SFBQ$8lB@H;+g2bF1EKHU
z`SOj<OwxuRU{-78l~xft@yKM_+vvcK6z=s7?d8AAGf2xD?YVwNQcWKfm~>0HddOof
zH$|<$xfXx+HtA>qV6Q(YbLgWIMjv}nBbBgEYas^@0aDcHFXl&aA9x1|TAG@Shx0Tb
z#R~}u0i8XBSl8YF$xOjnyKNL5gX!#a>%By98l;cR%o9n%>_E=xY!bJ8o*vTn{Yl-?
z5uk%*Z07Ad?Z-9;={qm3#a@Fq7pmDkT~~Fnm+t_LNqsW+@+ey>JIs3URcTXMp`~xE
zud}AJ*57h;2MjY+v-{`*AJwB`bRxb{<y}XhUjHdQY(B6qm(!4Qef>HxrGYOUkW5i`
z-z8Ci-!19<x9G@E-PWWqBzx6Ecb^{@G6n2-&%~D&dI0L|$6L;C)~QZ>Jt6q>JnvXz
z+=$Ep5a#3k<F!Y_1_3S+Tc#tXojaY0+V;vXv`dOo`&p+pE~-zdtB^daJZ5@H*qxYK
zUyHAwO3P_=!#HBj6U{JEOVk^<8Ne*PG`sLY<3t0zx*6GgP2(Ey!C~Ug9RjWqbCgjm
zDJWPAtP(gz*FVO_9$#K;U2ZcDwK-;H(De-s9Uj@S>87Mo1Jx+#8P=^>BF|r5%PY%3
zft;xf&QII)izJq{jrI3IZ{^~m)<}KPDQ_U$8x>RQ)pHQRF26Xqps$gNsQ&TwMu1Jz
z^yB;XHD7D5`NYL&MaxW$cvc?6Qg8I;Ni?WZx3iPBY3rAe8p-m}tX%`hvNbzwk8D?p
zkj(FQW97T30k$)-$B3DCm}2%%fx#T9qDFXw@Y)+>e78mHi~iP>(OLB~>PG)6_u<vO
z{-xT1nw`9U-tLOz(Rx**4aM`I*MW#1hUv|tT_kr5?yTDk+`ogI#)R~1Hok+Dnu-cy
z{;7H&JvB9YI=XW3Syxihq}P&76Ad7vYUJdKU}c}adsjnKeN<dQ0c^KQ^?m0b<DQcO
zgOZFYVp(i502V<_?jGWeIIwCbP(Pp|B3UC{%lMQX+JtG_sc#`R1UE(vo=bG#;(9M{
zWNP29&)o`Mi1<sh--g@#y$K<rHoGUr4#2U2{GXG96TD`gMXEjOh2w>ExAdaMPZ{_I
zI0h_yjos0S3Q5V>WI2fHH-Rb7jsmt}tFyDQv%a17AYkUHpP$&iN7wwQ&E+KBh}>d(
z&kH=&e*6LDJF3mh1Ni^zhQZ?)US>H3*UEuY1b7uxNCxn6aZAd|X1Dk0?x3KMM^2`P
z2TIZ4UDNOLeKS9X#)ZOl%y|9wOnn|YBEMB<Yh!EDthCoMBl2OuLjpkpUlH}y^3tNY
zU<nmQGRoU%uVSTXLK%24fTCYiR?S_+(y!DT{u~pfAAePIzYHcO1jVNz2eqtTTH`OP
zfVA%Em*{(*gP!|-16_tu;TfBPJd0e--&K5evMpe)!^-R<`R@&Abpi}3%FwpgX*O)!
zvKhEwym+tf;C4q`2kPjJwx#VTo=6Z3I23sfd2brwPe?Ztw*19AZ5yczUksPel|NOy
z^gRQ#Q>jZ@ERmg8@BND=`fjtZKS`|?Vb^|u-r#vX)JDIIz!uo@!1=(Lt+H}{<cr=p
z&uKr&&|@!l^tV_+HpM6+Q2NrddNk~K;B4dmosm<xxG1%#qP`-fl8Q;#vf|Qa*ClZf
zNXFcbk6dXz%A6~JMtl{DE$k4j?@TncMtMBuy^Qu`x>QOQArGhc2^c!<fm>f%b}?h1
z`1nRWe?CoqYDH>I<(c^MtssQ?t;nQMZz%i0#1iEb{aX3e{gXQY%r8%L=E@d-R^No(
zLdQ$z+vGPmSLG7r(&f@irMTs<=J>m(SGe(Ui$-s$JcHb}+~MSAN#ZP_P^^o3xn_C4
zUq4iA;H@5*Q<(GVi}EY2jkH!Cs`I9c<+tVpHwfITdbLWd<7ycnay_i(@tCV8E5g6-
zTlmzZ86b9QY$s$(T&|s(59aZ=>VkOB`(0noO;ye6a$Tjy;ufEbr;=uF-4OjK`qk{J
zVljt~`nD4zT1GV*%LJ=Z<NMu}yR>dJ(G0AWre58O!yj8DiI~}h>UV33KXPKC1Vhp1
zThzDcZ^Xw9?;`*Rpi!gYb>U`L))v<V!h`4Z<^`^%FnS>-Tv;wgu5L*kkKShR4F+>8
zmA6_AiY<j@)sYdg124xuyVuvnd-9swD&AHEy#0^KLLw{2gj*$-(5=L%td^ClLtJrs
zkZHPYG|n>DliJ8ovtSqLDG2I->UNh1@8^bQaeZEl^tpPd$4PR5Ds@}GE8i6ae(;<C
z<QDhd<A-BP4~!VOxmBJ%H7rgQp_4QAPOJNT(UfTuF~km=jQJxCBgLy%UrfMTSy5;$
z53dOF8=Ngq`1$GiQH_7Se}#LR4_S~g7Lv|N+%~J805mN#c!-nydJe0_uDf;kfPcPK
z6e%&dV#-|M=wG2w^6&q5?{{3ShyRyvP8}w3)6vr6p}&uySNNqaOhfZt<iYo<s!%h<
zD}43sgBLyU6IB2Ce<?{f)ATeT&xzriO-Lvz=e)}GI=c8;_qh)4EsLx@zZ(b6o%|YY
zQ4s?yBeJY{qh}(fKVVmnGmM)X@Bi|F#?aDa6)J)dX+&8@J#H$X`!5#&qNsPOYt#qL
z(M>*Cmp`O?vluh@UKlT;wgy5KaHsZavdFS?f8&nU)f+b}-Lfif$&1T_Gn4Ta6VhN<
zeN1^JVv$SDJwHE<O;>%lX#UrlOhQ)zK{EFfKR&@;@2S!L59F3X7C3R-bdmJuXX{JF
z8JsmuiY?ncC;SA2v~M2_bR1szyU%>T;>6L@(?cEzQ9Mvxpk=n7zdz2IzPR{%Xe&rY
z7XR^M9}u>HT0qBUj(Qw=%K^j3q~ozXlNJ+uZQW<ZsE1>|p7;p_zX!+C7&Ee|@;F~6
zLV-L$3I~pGC}_t!@z^Gp=xAy4*U@-W&57SOCKc@^t?wHcC^2sT1oTe*07$2RUI=&_
zV4}c%qSs}GDgs!WpP!#2`o_lG)`q`90|z*nzynWK{x|yW<n7tpFf6vksWE8sY=YU$
z*`2*DKD*8B>v8L%Yxl69jE_wmzZ=G_XFpC%3cb%P%OaET;~~_J<Q0dH{D22u@3trT
z{P`*nS)s=YU_8L469!p4WOtCIK|}XKOXwd0MGQc634o*e>>2cjb8&aC3J&fB=LwF=
z9qKk-+dezwf3_RA(JrhmE(z05_0%mdD^#Txq{{x))7d_1Jv8q;PrLX&`yFWSLWapK
z$?MlEZ@^EFGJ3kERAsqa+gYp15%F`K!ng5%<E#5M6^l<h>LETb2d>c{82J&7ZNLn&
zP_cmD*;`ob-0leZS^K5K(VuZ2V~cqjPJrhicqyOf6)-`4<LiP8>)>5+3%jd_2g(&M
zeX%PR1);62O)sASCcA*l0fl`AG!;dbkd$q1ZeA(J0Dd`y9*vNR0S6D{bZxF=kMlWb
zc&~PSt!k~ECz`XGYN|STv$q>?Ah1w)pR~NP^%IA?`H@;qewsN?8RvfHo8*r8&K-Ou
zwtlPOk-}`s(QR>1&N=ii%|4$k#DLgKikN)zkp}^S<}>Y4+A%`J^O?YfKXEVV=?5=<
zFPEzT3I{}BiQNg`%rst9cKPUDie0xP*dHYsD_^xuS2j>rPZ<4%-f@fRT%D<j@{yiR
z9fVaQkAfex@nV@E_1b!Sq0G^$ESXSQc?^I&xF+v>0`qA@;GzNu1VlF=!OdQmxQ&WH
z6kC-X-dx|JKIq0zOsD=jFg!q%M0}AyI|*?^7_R``ZFCs!R<Y1Sf>S42ry+?UGJaAq
z2eAUsG1;c2R5tu65|dF2_K)%R&q5<Wc_HZ}>G|x8C;64ZM8o44VWfbag5%cmO5w{A
z!ui`>c|9S_fv41GVRzqh{Z0S7PqPp4wC69+Md{xDh{06!UxNL$->SQnyOm>JJT7^%
zC$|$%z%I|Cq}kBk#W(1r6IvT0TypO-+^m`@l2(ou@t}j&a>XE4D?0cNC)Yy?J;&dW
zZCYtc-k#U;E0%mdzw!XKvESb+Do#Fl;Z)&B$%PvFxZ#pfl-C)Z=g;bRTAXRGR3<%3
zg7XbPyKQ<O2tzbn)j#sub6uFieGMpQQk44qz!Z!SPzXrI>B1--C~kcI#DgE@-u3z8
zg(9&-@xywmi>k!eT6)j*)Rdz|9_Tw{xsa`ApkJxfT&*5nJUNa2q6hbg--!>Hf`3)M
zAex82*RXWw`PY=xOq8qm$#&DST&d!Z!NRj|vT`gkXXnjZyVrM78~~oV{h8YvXmyl;
zaZ*x>Ds1i9c7b2pI-%|^L~7vH_viS^+C^7430lLVN(DcVws+$c^u3sQ`|fC3N>_C%
z(ZS_Drcji2l7O1K&2u*lX6iMY#@^Tjny~pN-A)x#Qw=hPGKMR+{sNmp&9LC3G>tX(
z$ib8|Lb~Aj&2I`rEH7ENffc>(v~JrpDb1#EpGSHvcKC`E0p)FwlEJS0QmA;uoE=;3
zQl(HS9zt7Dt+!2;%|#7+97_c)y0!6+#8-R@toN`GK_WvZB;*agXCO1-;N%3-9|-cl
zyY10Ik9fc4r2v9kw{C&`3ZMI5!0?s<mV*AmlM@qGMn+tL;nZ!1+3D31A6|U$^YyDy
z43fe?fP|{(^3ET^uk?KpY9HsrX@srU&DZJo^*p`o^iSs-X&Hqi{;Pzg;E@I<#je;o
zhXF-VScepyzBV<_rbFN_eAq1zQaY`<MQS_5!*JfsUu}%wdT?}d0?1UpdePgO-$O%p
zl0~q=t&s<?u>I}rA2QG$B<vm^r=2eq`gH^X^v5c!DiCzd2O3$tU_`twd2Mv5HK{qN
zuu89RubsFI4Z%i~4<s2-ilCJ%)L}ht&XlH6mT<U1%r!!y(?JZElbTbws+id)LJn*u
zn7)W&y>O^F{HIb0el;viOopbW!~Okyo=1h*E5ugnB&4J^({<-ZJ3xh70m3_!H=rZ3
zd66VAj7w-uZyKX%f2iEfZ7)!N_QGrc682F>L|;@NP8U|q$s*H5Peoq#y4|YLt|V3(
z_Wg9BPm7V|FH30Hd$YSKlMC@<?ks~=vOeuVde?l}{6{Mt=Kz;cZCJaL+>h@q$HjXZ
zB<c;j4F{x~%@n*<^i?Qtg8DvUzN1Fp6+E3PX^Dy=0y@L-+2^;QScBr>e0B3jE^hAT
z!*9C9#_dNpq2R?0`LjT;w>SSEXJxlf<=>sPT(rc!#f_v=Gh!C+W%D8Q3ydxWPLG>M
zh>c_nclZWbLiB3-FZyR%KmPvsP65}Q#@+mb<?G_t!(~GYLrdvu>D2{Jtz1k%3<6@B
z30KrDdvwzw<7T2(eDwFM?plQ<p9DTRqCVMrv?XLn!OqN%rCwksUgxcCWNyQ7kiz$k
z2^(>p6J<)R?k2+X@D+|}=qrcv^SzVgJDbe1W-+rR29WKN@87F0b^+k@*|gK}C;+z5
z0~+x$GBR;p9g+ZS6$2GDnGwBr-g2;(zsWXZ6z!81xu63JBU4Tx8C@`3J?g`TdkSTS
z!B@*2siUPK6`-WlSl8kR3C1WThASodM(3huD~23<fY|W?7lOZO*s3WSId8B~lw`6I
zu{amG?iVS$d7p=US9j*?b;JeN@#cgF_Tg~(u+Vd__pCg(5I~~=Y$uyChvR2I$iZ1X
z>ou+{iGeeE?M-knrXaWY#}&gFp}`C;S?n}y!yv<s_>NeT7}LP6l+j6J<OwPD-PEkN
zS;L#EH?G|<a+|BEs)5as@JKjJ<K-Py>~Z|h%Hf}s68py{7#kQl#a^Q|<MhCRtXr;I
z5Tv^>yjaXpbhnc%qBjH$Va8>KsS*s)TIdu`o_L&^dvd=Js~zjErTW*ZtP}Og2vJrQ
zO{Q*U!NP>I91uOjbz2lzQRv}M4-e3_(3S&KjmzBo9nJqi+u!|jQzVE~TQa~Tadj0~
zt^8Niy{8ePhhG;B|8S~tWbQJ;0{0w~Kq%rV-+k;DCi0*w3TP4j_b|wPZG3;f{dzz{
za~mDt4|u!Yih7{@lC1P~7i)Zx^;n2W>EKI3MR?!aa=ndujCM6>z$=GPOBmw$e?hP;
zu44o_;$LWt&WU|Rn7eIE@(xD<C~L=4p7sA&E#{9nsPP~G&v<;rUHZR-<WuG?-1$&Y
zhrRHMV@3N7MPzy(dJgCs9zDPMYrE<F#z+XxKv6-ur}#0u1sdJ_{3$Af*-dty@x8h_
z)no(y%ts~QlfnME2*&)OZVYWN=T=v9($mX4k9XT~Q13!7B2jR+gX97}k@Nf?yX)#+
z+P440uu~pYG<TWq;hl6TM!7pRc#FG$Z40PQr&0&bha1YwFX;L2!L2ZtcJM-s{Oo^-
zpb_M4+ZobXQTL-_xnqwEKu=DC_U=Jjss9xv=%XDa(2S-x>mFAe&HF1&=;ktf`7Ujz
zB>$?X^KEnl8PInJNdF}%EjRcHsv&zYmb!NB;M&uBPZ6&nYHbgN3~>e91c^X^L<*qt
z*G^7}>sJXj@_q4pGmTzI?PHc>O#^#03o3Qr=)9?Uswl5$ZewoclAH2o)-<sjlHdQK
z$%eUiW=CeTDY3;n@>m300WB+DC!)Khsa)Nz$S>!HugI6IROW0C_61#2r;OVHeHH@)
ze%O8x?-Zzlv*WPkxEQ&EdI#)PyZd$3d3NBF3(`&?hfuSF-KPo|%NYB;f6z8^1Xc-$
z;x1<ose~J-`x{>&<IBJEsM^mT<9R-RE^82CTUGEa<JD7*r$$n9g-A$S=|6+PMxqnb
z`pZ{Ztg0jl1oti|&ps{Cve-4PW(8-@Ilc5#F(|Y{Hu^v51G?q`!D+U5TVsdA(8+2c
z@zwOWx*U!tPe^^9zQM%7S)89w_<S{QNnu;~PG7~<$6-A@mPemHGCs5#u}PqZU*GDZ
zFxbOjinjPA;Q_?ds*=O7BMwRo2|IiLeSTo?vBs043xfafg@{RE+xiF9`lfOjP@9`c
z(5K)_=3cehev%ZJRP0#{5z@0AX}hA=NUA~6YWaV>&CtWt=Mby>c8TW3u>`t81o`#1
z4^nrw&&3c&9>>$FT;B@uWw<-#aCw^}n<VC?Sk!bc9`AD?v`cHuQ}o}e6e^ZIbm3(;
zXZTV}3`DZ}Zf}4p5rv8dUqj#b`1|k*xL<w{up)$*do6@*P*ixqWKDu9Jgccix>x$t
z4`#F{l0&y(2c**QXiAETG^!l4L68g;rtKG(XM15#$gZg1b@KvB3pBHtnbEJIVQ1e0
zt6S(|^N5S<6b!+XUob`!ox({90NBVkEi+5YD(HCwY>K>^l$3_i(Iber<|B(5U`e8g
zK=M;mWC!M4K*-<m0jv=BYOVs^p8itb+xw!R{-O%ny+HNra?9tE8W$Mmt?&u(;gH0E
zYj0tBxo(kRGkBQ+tINMu81y-lpv){b=`6P%!>6Fo)6tQ;&oyNa?rgBGq2>rxrw_GH
zGVyy0iRGv4!A2G?@>^aWH1~tj?yuot9_uc2&d7zq#X>Mp$kCX+lBv}$x+B{1+tJ?C
zR0#kn?<&RtO<rUUv(#Xx{ldch$_!AtA;|(x;k*-^ZpzQ@THJC{1R&`|`Q+tA>aH^x
z>~Ge{g_0J4gE29Kq1$~;6G-g(`*$E`LVzo@4=e%j8RQ16Lq!FF4%8rs+knlJoz19v
zCCY(X$Hv-PBaYb9r}^5IvrxpHnRyd=m3M((Fxc|B5<^!ZeyBP^uY15gK<5DlVbAX4
zt7c_`6$$9FfVPh48ytLp{^lGDrG*>xsJ5epUo$gr@?+uP)cpsoJX{|`0scR%g*Zq^
zJ325Fg5SM;dv<;f)N_yl`d0}<W(ON>GX>dikP<<IOaaq86G(%gRMOTaomU8jld%%B
zm$P>d8W=U9F&M4t5%hEf?H?rIx6r@vYPUHKfexX$OM+wleY_tT{|y9$c>*i~gvkv|
zeKs>>X7^Q-I-;KMUL|}5SWb%n$g3|}V@#0XVF<-*P;!y++Gy8#@<G}qD*6*19whn1
zteVDVX07e*D{E`HnVA(JqXDrDAPbPN!EJzZ2JtC3DH&O{$Ds`lPAK#?1ragW8Uj86
z5>o@1=$OQ8pTol~tgTB63(c*q2S-L+934Tq3(B{hy*(?N42%A8u!{rHw^En?&pjq>
z35jM%Z#~@IRSR@q85uP;H4)ys=LveoWbc#qzCJ~u3gr^v<2SUnx&X=q>^4xB2w$FY
zfi)tmEixW!lF~yE`9q;MTsjRd6Z`{;3krHcfi+rWgklBWl=gOZeEj@i3s6{G%)`yy
zkB`gxR7?!WNjlovplF5~KJe(`BO)ATeq3W`XCEgM{m3ZsL5!iEvOeRRWQ-UIJJ6MH
zA`IjW@}4S*DZMZwz+GGV9qu_~rD?3{qf}p;SzGw^b(%v&0QUbLXW)ZCIp61ee*~6Z
z5HYl>f?*$qxe9&+h?goVlOTA8*Tx29!qwH)P_A}$b1Ui~X48Iv9|(jWwEwTQua2s+
z`~JMVN(f2`5)v<<AktFOFCZn|C0qmvNolymMFHs&Y2hj%0s_(k5-;7|sURWU9kcoV
zW@gPFv)0U-HP1hH!Fn#7=RD`^{n`6`_GjbZ=(UHEvq8HdkT9nQ))O4vLG%G=zrdiZ
zqqmo6(-bD0&msb9vLPh6{udnfkB*Ibe6a?a+UnX`6Mf8IelP@3U;w#TxT(PSeDCrP
z6(uDwwcwR}lZM)-+qYw({pzRU7BCd<z>);p(0F?U$X0ga#m&>xsp-ry^5Mb3aLis$
z2=iqX5_AXFwWuhKDxaOLErc8NVknpO34V|On3#kjPBS236YbLzN{Fmk|LN%LAV7qe
zhX~F&m}DdB<y#)qiC^lq6@fMf)ID7LN6$DBU3D3Zx^YUpn6eSZ@o{i`(v$s25A-nb
zhsn+Eu6*qK4&M87Bu^(blnW9dfc*g4-ea4ONkan8qhn+Jb>Tn&<f@xnCSi+1!;9Do
z=vWD|^L4T4@`?%y2L{j|MG(>oKk4TeJZv)-P!GCAHC1GW>-h_g&Vh9+DW0q*Cx@#_
z^&kCB1Ux3URtdx{2){b(*0IS+qAqHFKEAE@F$W%2pK@{(E^MJ?R6VG|Ha0Seh!}!?
z{1at{HnJjRw4sU4&y+dA-GZ*z`2?F)d$#`^#zOl2!HtJl^*ZPIzEr-D6EDO^wiC3W
z*N*gNo)tX&nyeiQv7oC-MQC(K%#vJ>9EM_!?4dQg^(u5YdvWTx5p^{SZ;jNQ^!|7B
z?~mq{S3b_kES}$V_u;pxn7?>=ck88vg@qwk6nY0LIe`v<Qx5b9EW}t}Bgw6X)y?b!
z3rjU4BO^q8Ypa|w2q`N5P5e!hG8BL8mF&am=l||*dGplbqkEpJK(3f<TaA*BG<0U$
zqTe8{ZSQ^?!_g+u<yG{q79Xu0i;V!E2>C<$L^LAr?*`Vn%AVaNO9^0pXF|CF`1`@x
zmhOgB?btvuRAzH-Ql1i-64YpXeVK=apfXM>S+vaZ$ZQc9a@6Qki&l&Gqo0fQu+lFe
zl_U<B0#gNNUWiv<&ms32su>=RL4G_sJ;jK)+qb{F5Bxarg+7NHso)Q1q+sounEVaJ
z>oNq;Vb+5JBsH1QZ9$D1j5{HZwq|dOJHh@qS*5#D`-PU_T54+b1hMa+rjpdn+T~ks
zt=D0sD65i!0+n8@>9@0Q+kGCt5YaI){ey$j;z(RCZ%F#LpZ;dVTgS2AVDDr({TYPo
zYUc_S7fLsk@XzqcZ0K{ta)ay%IIJF6t-g$1j9GlXFuqYji+JH-Znf!t`QtpYDpDpw
z2F^C&_TOk#$XabqPA4qJU7V=3HgftK+3=4Lvg=-9{er8rknr&i5nyy6UO^}a$H(4A
zcbS+nz?$vsIDLg0=~`eML3#zy1!$TeH8o41wc}Y%B1kL9$puA4MZJBCGxH`sUI&E|
z7VsGx7$8Ml)YXVY+06BvA}&&h8_4Cq7ryfExSyGxE}N52UaFnznm@A6P*7v*XqaDS
zW8-=%YT$0@IzF+o6YQ2_XjgQ{CwDAYEBLx(sFO5#11(`C*ENMS2@9lW@!v_W0`f42
zd4;tfkQTnjJ>i8v#4jv-c{hLT_C!fse7P_VdE&G&B_svq>=A*1&ERSX2rkcWhQT&+
zpY^Fgrat4;eHiyJuH#>~d!nKrh>L+{?z;7mi)*&noPgnp*r*p}n#bG?sW#ZN8`GzU
znsdPZ6F>TSt>qTgYQJOa4F>Sr;7xtDequ2^$<hFJ&oX#=Fu-s%&T#qh$kt8i*Wcc=
zsaTl6PYt{{xVYv#Ha=CtZ^v&uVk{Xcd8g$Li$m%Ux5MP@vTTdA!N9;GnP|=Es0h_M
z^u)IEk+ac~aH2@~4=taq;sew&lh;?J{6s+<L?5@cSp?*|ATti-&5)4>eitOA0VQbU
zlxAlyLAy_%gK<kR?-<WTs>)|+(0^}f7g+9)uc-kQOAyULUtXLCL_?=NaHh}<D+82#
z54X2}ZF_*_20lK1;2YnM^MLaJ|G7gKap-mc&i3^`YU=6?vF*@vyv%y|p_IIq*3hrU
zAb)><0CV6=f!7a2A1LPIUnRp21S&a5WCFXH{Z5!M(m60Y4P_07s_<*6Pklh<Yy3q<
zPTs!Y1Y>~=*K>LdIh#%wh_irS2I4J5J8BQefaV4iHQ0#PT6Ka9qBuoV@V58&#T@6F
z05O8^g8F9jM^p?iz)UyJu=*)5<UD@4)STLLr$^_r4mk%o$23Pkbj6)o89Y`8PW0xS
zm%kn594RRy9#ypz7J|9F-@C)z)^;r$<GZrFtY={GFh(96{rjg2KvscAm&5a1FB=73
zw)p89uj|uEXh;Ca6o_=Mel=iA;U#p!3Bc7IAcPL}i}y%Fv>q;Od%&8|R!t6xin>w|
zifYY+=16UA(d{o7V}j`x?*(`t{R&b{;Ed~BfI?V6Bv%cP+}8B!7@>G!^XE^P;+W)Q
z6m%0g@r+1*5DIcdQy^I^qYk$Mdhqe_fr`Q^xAo+ZkaD>rYmk$H!2|+L57q&ATQEbA
z-W~{1KJC2enj@D$%MzfJBCrmmEL(vT-yM>u*06{Oqv`{OgaX9pcl@tyK5%@<GsuJT
zL4zto+b&x|QBM;{0R%)B%oK#fnZgCz%Li1O6EIoCZ&S|bim_x;g`8y-htzVkU^PK&
zjc>5|ot-l_(_=dqKxBi4Q0`od)&MGW-P{DCS_eN&vL$qeg@yvC#s2Fx^fL_`mY6u$
z--lx*H&<66Ru5E&TEBam1;`n|DPU2+gK+pmhIc(#5PKj+P*9L9t^>jpaSSFo+1lQI
z#-R`Dc5A+W*ZZV)baZ5;BCGx|4y-cZlVqZi&vzlU1B<bYz8*^4f#wKdj;`*gKQ58|
zWcfOz-neRy=1jzRM>0AiK}rBX@e^5D(8f4)suY!wK;~#c&sz}O8X}TW2b0~IAaN#R
z$*oYc-E#LCXT_{x^4m`Z1uCc2fuL<<YPu57g(2Rg2f^k2)P1N$d`37rIH4)#Rh3u4
zR&l@}h&9Nr%)b8Jt@&27eZ2iOu77|v{i^DWkmwI*S-)xocOnE(yB<FPZKAfJTmaSq
zKnW;J?K|`)>mK@Ysv{qvIpDwxqF`q@5h!b#ZbAGvZU8vI!bL*2-s);EW#wC93RY0z
zk=Sq(fk51**O(uJa^9nh(@lq|@6fMZ6%Pt;d;ttz9mdYMV!=(^($+L0fM`sMzJqW_
zX(@DKHfaf`VoEaRy+=dHA|&J~Pb7~EH}(Y#JsyE$FFN4_nL<7G_;_81YggZ=?q=D9
zPei>|;1F~{Kp?uJsjvR9AC(5^wq?2q9DY4)ol$63m^Z>hoay`x<A<x{SJx+Tm*u`T
zBs*3tw3M3yd)!)$PpJ%Y1$RQ8%o|}N5K7|GDiJUZ{c^P2SU0Z!1<C}R2_iFr^;S?-
z2t63@ZazdHOm?W8teYM%A;L4>54`{4knSc{+d2F1rCP@)Z~fZrvZZ!Q)t-=~k^%Gr
zi>i-Q;epYHyNK`Db35zQ3kzWx^?>NA$SQ0MhaT6nOZ6i;Go7(RE+19A_OD%MCkLYy
zc@CrHqfSE4K9y|6_32vNu-KneTV_8~+(9~-SIXLEG#iJxi`9lXH0T~eV$O|w;pf7;
zPCGF>aRKrE^yPM^7YLJ%dd*ralbz$NlZ2>3pRa1HcnnYD-Z?ZJmK@$r2+@8>o*K}k
z!4qaWy;+4EQu}SQq==`$p?p7p{S}g14>NfA$mo-n)v?B1-jqGT!5}S4hRjbH&(CxA
zSICpAQwpbR+|FnA3)4=m%R6mdy$aY53nebK3!-mJRe4qSE~MsJ=bxY&NB6RcPUvip
zM&CA^NTGOC;}1K=b>n;W#0BJV5Pomr#l`k!r7PAEoJ@B*Bi$CNslVOCV_+oeS8wl!
zdUd21GVZBs##+nM%eYI!t-74792Wu7gb;l)o3s?)!X6^_@bm{ULCb;qTu0-l<B8*?
z2c;HTFV>Epx2m_RcMo}pU!FNPED3avzi_a}aCM?r&kU2|l0XWk_MkQ(8f|f2@~yUS
zaKgFww%40f|CFj^(?K&;b4>CR7~W?@rYs`S`%UVbLz%S<++Hh2cNms>k=B~crlB6v
zqi)srsB~*(#JWi9%xSq3e0aVnM;}kLW!K%Wy>qn9Cl9(>x-7iL4$S_v&Zwd;eV2St
zWYNSLQ(N>%mL1}Ap|jpSjO7iB8k&=xH2Om_ezN`?9*_x6|H70Pc{FxJET!c6*{ks|
zo<AW=VUUu5@;C+y@$px?2!i_<-qA;@a6E>R>m^Dzl{GpwZZOO}D#9}7?zKy6lXl75
z(E;@UNgqi~-9gG{0knE!T*Gx|oEPp1p`63+LwQV044K)5a?WLHqiWqU6tx5lnVK^S
zT=5m}C!N>-w0)^oPko9&kYE&^NNSb0nZ<BoD@8M1LueveKu3M2{{yoWFCX`Z`A2dZ
zoPYkTk|;JySu%_UvpG@FJ{5YepOnPa$r8Z6r}rhRSG}^((d4<@eK{}k8d#Xw*V4+D
zCY*0RCX?ZaFq#+|&a6x(nUr^qVI;f4E-x>Ijqv~LIiG`M{AawFAo+sm?DwCia(~?4
zAtsUfi}u<v^V!gVR*{yisTHHkok$;TVB82;2=u30>DK0vOa`Za35~~p8S5gS`h9zP
zMR>*6?o7LcCyQOCwVP!z2Fp(Y*DM0TEz@_+B1n^{lYA#Ijo=0Ydnow|HEMmMEV(=x
zn~q?N-LB3f!wEV6kIEet_s!Xe-cYpg&zDm2I@%*><hcV1Rkp!s@nkBeret9%zDDs7
zM+m#W<T=jF(BniBIw}N$+Lsk!61r8s4NsfE_kJtf^EKgXmwBn)z`c~@R%k`N->^Tb
zSh#uqa&rcAFu>t^;5%rW4X<W(rk$X~_%Q}u`>l5CxDb<V_#hNDaM(_dkM1+y4e^A1
zJ@7BNH6l@XxwCM0YO&}G`tp0ol+5`BcT4;cyU_Q!pEs+iT5Qck3Z_xNPLB4sX|DA|
z3-g%XO+{@C;rzn6%X^opJO)!UOOaQn_xm_{oZCOi4^}%ftu>{);WY%bM~1#)R{H-=
zPO>q7wm){VTLqhXvAiR)2I4|qL6o4V3YUdEWP`!@-pnDn`b=c_FZ0R^TLvzZtDOzk
z|7w!qN3i+-r!OCMx94~7UyO;!(nxcSlnyrqn>}LV-5-+3_;iPR=z=Aqy*etk!U-V@
z|9>mR%)y?XBQ$MQIKenm+ECWK#bcOv16%2z^Bxj}()G1%P8iD9amV#^nSQYBR{qY{
zxv^lR^_l$>gC`65T>hzVC_FjS4IzQeN%rg;Uy--($gYbbrg(F=wAaVhJHA^F<e$?L
zG2h#q)uYY&x<gZrU5_njN?iY4T@hJPofQ`wb=?4g7%(c9&b_2k_ZCP4H6-2Bd)V;f
zq!{DK1j!CrPoZYLL9{V^Otz5?nhmmN3uKq)$J;dBa>FNlh4*o?jN)VU0q#0$7Ave|
zFztvSzj4lz(|ol_ofL1b%5%wTK;ns(dJ1Oks`n*0Fhx_7EnXg8P4Yfxmcl(sv7gC@
z$P=lO0zKc}@Oblj)k;XNYBM9A`eYx2OhE6C=AFA??7asL6}W7;y6xbJ9dxF;a=Kwf
zaO^z$ZU0AnNSX($m$052JY;?5bNd$;y<gFv<Fj%#%}jmgECt1RO{kun$Qe)?5=#~5
zm6$d0h|o<-UIE!ClGax@AHyyR>ud@jMtfae&C0~8X%o*Lb{~MYfDhND<WYdFJcXw@
zXeTy?rpA-Mm*ti{HS)^{oQL(NhAU3%y6;x=VXL^xd4jQ5Mox#8hlj6U!*AnVXzWb&
zk@2a&n`>B~zQ>DU5|IMhnxpPihl8{4as|<O5<VS=Ih2lFe3LH?oZ4rb(YhpY@tgeo
zeCLf*5;qTWPL9y1b4`WH0Q(muV`$WwDpwck)2y&TPfX<LmzuY}=S!VCxEtcr%Qj1S
zDiJ($l((g0Gu~zB`qoGln$<rVtFygasUJ3|Eu|MrrS&Tcx^h)GVW!>gDd@`IPB1QK
zCTA&m>zBC%vsuMikHGYsqOLRCD`Sr%X51mpsR->1Uw!AEzh(HV!`+qJeR*_=CPB!?
zqClZd0ne2n6>R6U@w7qBc1i?zZAleLh{I?ESXAQ^jMHj`p6{xrpy#L^UAd}vB`skJ
z{iOX0Qwt-Klqdbm!$ZRXaWK7<D-W`x|B9F<AECJ5*^ct*sQst4o>)>o=*Rri_PDi`
zHIAin@7+^}2caD~-N!$7aPhND%RASSB6(A)Q@ALQ7e9`jThb&HPnE>Zj@7_~8fY*@
zh+o89#FRgq1Pqh;Y^Ogi>hq+^D9w{0-$<8nIV0=7fw}`b5jq!G5EChrFoh2C4&F!e
zL8?k#Z!Ye($)hcCP1de<*bA5hBlfC9W@Q2l-OR{fylz6pd_S!tmE+tao>b~)b5k}=
zHlzr0pLx1wdPy+tu=K#&DyYQBLX#{mIu_j6O#HFo(E6qPrJSMa<V=>AplGq=w8zd!
z`(@P*a*3cvg2h|qFu788$^mmZGSw!UC%g&{R{C0FFcpcmU|zv=O}UuusR{P-2HO5Y
z6;tdmzZQW;t*N^BPHZnn4kHVC3VKuu<uOYFn@<*R1Zos%m+mX~r|dC<mukBm6E0TA
zb9t+!NVY`<@XT#N=79|NfavdC-+gosX?q_RBvF@Pn2Zi$ig4D?ZTj<;YxaT^SMpXw
zxHgp96xzOad3T-i7zvEdj$=`JfvMt7>hlja&3WvN@-XmBmdYXa41P-ebU7?4Uo79V
z_y>y*W{Ac+bT5iV_L)4JD(}ae$yLdbnY8LTS`Xtwi3i3f74X0=-fv)VX-?N`<&9(^
zXW6%LShJ<E)+UP6jx+y<%9ddA^Nfw+?M~gLnyS?SXn*|G(|#8=tny7|W8_v9>Nb|@
zHvucVwQjw2u{`H4`LBD1Ig#N3(Fsz<!puVP+HqNxg!4kCQ*u&mIcu7SBAa=F<6CVw
zHkvlHr=zB>_14{YdFc01d<-m~3TjkZyZ7DQ5G{0owUwB`Nv4gY0XPdFc1#+Jv=N+k
zs{#}vaA@o4><JP?8d=YN*8bxh`@GBO?*Kkmepao}x{ynOEvD|fLoVBazr!-;?y+g+
z1=11FcF{hzC6xIxSfQG?X?FKhIj)`Cq8qrgZdu)0Hipcy?6`|M|4M%>^N*Ep{J8#B
zlJ!6`bq8*ySGJ|=^@uJ#(=V`K`tMJntB*XNILbR21S!gup~pY!uJOqc$aTx0JjztZ
zv*#C2L_`o~MBu-eldv}k=1S(Wx-}e=66sK6p1}`7Nfn!qi@kR+g8ZaXH}!CcHs#p}
z%m^x_YCSg=U(?@mebdl;=qq4x7kScn-!&Ls6msU|-L}0btv;pxQ2Fq|-oBM=EFcjn
zyxv5)OXLWr<`=T${><DgYZKk`@D85{F!sq|594yH$|f4xq)KA8X?Ql67=9m?_!bI{
zSlL<RXQ8VwDxTREX3B;U2an!L{?EO2ucXiHxwp<4JfL=&PR;s-07KJ2)4*ttU>RQ-
z;MvXzn=ga3;Wq&vLgFDgVt0BGQ|a8&J-{(=DY3!LmdiEZNF6{eqi%am;GCnB>mCwd
z^N#Y70e;^!`@dhC&YGlIgJ!(e#HzBgsu$@0Tz-^b48Thbq`>E-iKX%Kxv1mv2iNSK
zvddxCdxesY-|VV8rw>u&s7?tx)~(h?3S#G8J<JRLSB)PhiGDUYGX~t7RrY1xqN>U&
z$k^yg<(1BTO7XwEfXV{rarOgPcVsd-LF5!D_HZzt+IzK>J9BCxF2Ab3Js7DFnmu4W
zg;4ee18mXJ#kzQ{52fo3<+qbq-q84WMRea4rhZDT=w#zOKhh$!`@wY+xqPoHzuU;s
zw3!rhKOh=*1XwlUM}#_l8|MzmC4Yh%=p!v@>a<-~NtWb<>0F-Gc$MYkv5v7m9^!vb
zyfd(t;QQe0mq~}DW0J?`!LG%E#m@T){F-YfvJ17c;4Z*S{2FYut1QQM#eO-!7n%-n
z24AKM<)P!3zi9qi`|bw8XKyNsb4=)aQOUN`wz(#uGalWt`~*pshR|5i!2d7~A1N|i
z_V*dO9$QFRKDRLcjH$uI<&aN5*deA>l#s>y<F1*(dBl7+{5tQp6Dh3IKk-)TrG6~I
zNcuW>eo=knG<MaR;=<I;Xhx>#6foO1^Mx#rREed=*bn4L=+D_skt-~c;-v`49+n)6
z(0Crzgl$gefY$9I;k3L2Npvk9-EYcL_dhcd$YW>F96O(BFv<SeJQGHgMKfUj?Nva!
zg<MvA7V{#@K-k_cb<j!fKP^5q56#NAaTUdn%;xBaTc7-9Kuw))*GR0>TI<T$)2M$T
z^UrFz;p=9CubG2KwT>|bWY|ZbscEj8Q2TBkjJt2nh0N~DNrpGX!Y>1>&M(_yQ?d+8
z9~dl8p&NGVK~oM{j?S9xcvJPJV20B*0}yMoG6g#4;=XG9==9{e$p$xAnZg>b=L3c4
z+8dWrLxDE#g$gN|kj)Ger4Z78%&Of{o+hx4y*wttaL*Lg<Xv&hYR(FjFz~Z|4Buua
z<wgibgFFL48D=Bez0ZMu+{aUpihEd^9-!Lx>bz#BM%ZeYve4%!lvu9Nef>k{rteWi
z{CbxG(LiLvetiARdvgiK2EYgG2mT5Hpv;x=5u)jM`wxE}YfcxN|9b~s^t+DM?X`Nc
zk@0rMfLE1ITlih&`lDhI2+DWRaS!U*IoL$E16DiY)*WicMJ?{XzT;UeiuOY9e|wh3
z?qGLjP(Y%)^Y(>DNuW!NMl$KX@=!smyWNKxbyXw}e|YEkYiMyTrsDCvGms#zwswMU
z^e4ddg+X8L5j+Hn$EQkE0&P8$GThg{wZC47dpa~YvCBG}&1`UqzI~a$=le4F@1~BS
zT!5v=_Qg_J9?wSz@b2Hn>LFZ~Hl_>e*75Y*k2J-A2m46z>C-g&JWtz!%iQYmFsBut
z8-Gi%8P2IoNbft6&$2#y^vlFYyET~3l+Iy}-s|GKD?fCD^clk+exU6OdQUbeNB8H~
zE7@HNO5HD5CXXo#)jD6SedDf>4ubsEX!*noKB`vg8w}d{+WOl1ki}YTS#*B32w`ye
zN7>Z(f(a~(ESx*f$kxcdZf+*8wOp*#55bfsOU$mXSELww7ipg+OIJxn08DHAHxd3&
z;g7k#u{IU?F9WmQ)-c--1mfv$o87;o=qdVkoLl;7#Mc;YYy|h0^~sc-oySW(x7L%!
zAVMLHh`_<1?JGT<3Cv#5JiJ=86!i4RRjzgzZ`0}i*BEMqAJ0xZ%LtS|cc;i*lH56B
z#YKprR`V^g-u*Z)Pjz~K*-U^y5N%JpFIx5{Z%zzbnLawH_?wacFF(5N<Iu4&gOH}Z
zdaTv$0&EBot6e*f&JXR7K4n6pKQ!sjncy~GY#i~iib8SDNEmV8xH|%YdYAO_Y$Y!;
zN^E3*#84S^f-hP~g4nZf4vj3}90{VIcppdQd*)aZL(%}bFRPOckzJ!|TYB`5)mYUP
zJ=9&&COt@01zKY4!ou>D6?lwFT8>9J=C?U<VF*^Xd}Eb^8`JLV0(RENr?ciQEvPd~
zA@J<sF~_^rb*BX#69z@THM^4zlZshy=Z#1Z_4i=zLn9Wr^yiY}Eu4M_+nydU`$*7G
zs2=0^{pwp_o%OFo4cpF&uZH3`3OQFLu>T>&_nMkQd5Q*J6y!pR?G`O9ds28RrdL6M
zr^cySDJN6F!G8QlrRNy$=WTmRL|=7GrmR%3lw<)?Pz0Tpl59OO5n76e;J%K7lN%kK
zmZd0y@vZU+h}w~bn6l>Xb89Wl9C_EW=Q7yU`4L$fzq<Vqh>64`Ry$j=nHeWSOP8I=
zXbq-CwQKbr=?@r*_wcXRTqOn(-1UJBSE1_vd&v5qFAL)TC%woU{{JZs{=XQ}C9bM$
W&)0NyXS%ELE6AukDUdRG^WOly&*4M>

literal 0
HcmV?d00001

diff --git a/examples/cmdprio-percentage.fio b/examples/cmdprio-percentage.fio
new file mode 100644
index 00000000..e4bc9db8
--- /dev/null
+++ b/examples/cmdprio-percentage.fio
@@ -0,0 +1,17 @@
+; Read a block device file at queue depth 8
+; with 20 % of the IOs using the high priority RT class
+; and the remaining IOs using the idle priority class
+[global]
+filename=/dev/sda
+direct=1
+write_lat_log=prio-run.log
+log_prio=1
+
+[randread]
+rw=randread
+bs=128k
+ioengine=libaio
+iodepth=8
+prioclass=3
+cmdprio_percentage=20
+cmdprio_class=1
diff --git a/examples/cmdprio-percentage.png b/examples/cmdprio-percentage.png
new file mode 100644
index 0000000000000000000000000000000000000000..e794de0c0f290ff3c7fa30757f287c1de052e0ca
GIT binary patch
literal 46271
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
IsW%_~4Q`gAB>(^b

literal 0
HcmV?d00001

-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 00/11] Improve io_uring and libaio IO priority support
  2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
                   ` (10 preceding siblings ...)
  2021-09-03 15:20 ` [PATCH v2 11/11] examples: add examples for cmdprio_* IO priority options Niklas Cassel
@ 2021-09-03 16:12 ` Jens Axboe
  11 siblings, 0 replies; 13+ messages in thread
From: Jens Axboe @ 2021-09-03 16:12 UTC (permalink / raw)
  To: Niklas Cassel; +Cc: fio, Damien Le Moal

On 9/3/21 9:20 AM, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@wdc.com>
> 
> This series improves io_uring/libaio engine support for IO priority,
> adding options to allow for mixed priority workloads to be specified
> more easily and to match the kernel supported IO priority features.
> 
> This series is based on Damien's V1 series which can be found here:
> https://www.spinics.net/lists/fio/msg09614.html

Applied, thanks.

-- 
Jens Axboe



^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-09-03 16:12 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-03 15:20 [PATCH v2 00/11] Improve io_uring and libaio IO priority support Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 01/11] manpage: fix formatting Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 02/11] manpage: fix definition of prio and prioclass options Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 03/11] tools: fiograph: do not overwrite input script file Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 04/11] os: introduce ioprio_value() helper Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 05/11] options: make parsing functions available to ioengines Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 07/11] libaio,io_uring: introduce cmdprio_class and cmdprio options Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 06/11] libaio,io_uring: improve cmdprio_percentage option Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 08/11] libaio,io_uring: introduce cmdprio_bssplit Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 09/11] libaio,io_uring: relax cmdprio_percentage constraints Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 10/11] fio: Introduce the log_prio option Niklas Cassel
2021-09-03 15:20 ` [PATCH v2 11/11] examples: add examples for cmdprio_* IO priority options Niklas Cassel
2021-09-03 16:12 ` [PATCH v2 00/11] Improve io_uring and libaio IO priority support Jens Axboe

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.