3a0148e1ea
Resolves: RHBZ#2101334
908 lines
32 KiB
Diff
908 lines
32 KiB
Diff
From 943a7f434b10c19f8e8e865c3cc40685b9903822 Mon Sep 17 00:00:00 2001
|
|
From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
Date: Thu, 24 Mar 2022 17:32:43 -0300
|
|
Subject: [PATCH 1/6] Provide a maximum job length depending on the
|
|
virtualization
|
|
|
|
Identify if a system is running on baremetal or PowerVM and provide
|
|
a maximum job length adapted to each case.
|
|
|
|
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
---
|
|
lib/nx_inflate.c | 5 +++--
|
|
lib/nx_zlib.c | 25 +++++++++++++++++++++++--
|
|
lib/nx_zlib.h | 4 ++++
|
|
3 files changed, 30 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/lib/nx_inflate.c b/lib/nx_inflate.c
|
|
index ec32b4c..77ad33c 100644
|
|
--- a/lib/nx_inflate.c
|
|
+++ b/lib/nx_inflate.c
|
|
@@ -945,8 +945,9 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
uint32_t write_sz, source_sz, target_sz;
|
|
long loop_cnt = 0, loop_max = 0xffff;
|
|
|
|
- /* inflate benefits from large jobs; memcopies must be amortized */
|
|
- uint32_t inflate_per_job_len = 64 * nx_config.per_job_len;
|
|
+ /** \brief inflate benefits from large jobs; memcopies must be
|
|
+ * amortized. */
|
|
+ const uint32_t inflate_per_job_len = nx_config.per_job_len;
|
|
|
|
/* nx hardware */
|
|
uint32_t sfbt = 0, subc = 0, spbc, tpbc, nx_ce, fc;
|
|
diff --git a/lib/nx_zlib.c b/lib/nx_zlib.c
|
|
index 28ea482..a50d6f7 100644
|
|
--- a/lib/nx_zlib.c
|
|
+++ b/lib/nx_zlib.c
|
|
@@ -64,6 +64,18 @@
|
|
#include "nx_utils.h"
|
|
#include "nx_zlib.h"
|
|
|
|
+/* Use the following values as maximum length of NX jobs when the OS doesn't
|
|
+ provide the value itself, which is the default behavior until Linux 5.17 */
|
|
+
|
|
+/** \brief Maximum job length on baremetal
|
|
+ *
|
|
+ * While the system does allow up-to 2 GiB as the maximum job length, restrict
|
|
+ * it to 64 MiB.
|
|
+ */
|
|
+#define DEFAULT_MAX_JOB_BAREMETAL 64 * 1024 * 1024
|
|
+/** \brief Maximum job length on PowerVM */
|
|
+#define DEFAULT_MAX_JOB_POWERVM 1024 * 1024
|
|
+
|
|
struct nx_config_t nx_config;
|
|
static struct nx_dev_t nx_devices[NX_DEVICES_MAX];
|
|
static int nx_dev_count = 0;
|
|
@@ -639,8 +651,13 @@ static int nx_query_job_limits()
|
|
}
|
|
}
|
|
|
|
- /* On error return default value of 1 MB */
|
|
- return (1024 * 1024);
|
|
+ /* On error return default value. */
|
|
+ switch (nx_config.virtualization) {
|
|
+ case BAREMETAL:
|
|
+ return DEFAULT_MAX_JOB_BAREMETAL;
|
|
+ default:
|
|
+ return DEFAULT_MAX_JOB_POWERVM;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -659,6 +676,9 @@ static int nx_enumerate_engines()
|
|
int count = 0;
|
|
size_t n;
|
|
|
|
+ /* Assume baremetal by default. */
|
|
+ nx_config.virtualization = BAREMETAL;
|
|
+
|
|
d = opendir(DEVICE_TREE);
|
|
if (d == NULL){
|
|
prt_err("open device tree dir failed.\n");
|
|
@@ -712,6 +732,7 @@ static int nx_enumerate_engines()
|
|
}
|
|
/* On PowerVM, there is no concept of multiple NX engines. */
|
|
if (strncmp(de->d_name, "ibm,powervm", 11) == 0){
|
|
+ nx_config.virtualization = POWERVM;
|
|
closedir(d);
|
|
return 1;
|
|
}
|
|
diff --git a/lib/nx_zlib.h b/lib/nx_zlib.h
|
|
index e84bd7e..fa73b01 100644
|
|
--- a/lib/nx_zlib.h
|
|
+++ b/lib/nx_zlib.h
|
|
@@ -129,6 +129,8 @@ void nx_print_dde(nx_dde_t *ddep, const char *msg);
|
|
#define zlib_version zlibVersion()
|
|
extern const char *zlibVersion OF((void));
|
|
|
|
+enum virtualization {BAREMETAL=0, POWERVM=1};
|
|
+
|
|
/* common config variables for all streams */
|
|
struct nx_config_t {
|
|
long page_sz;
|
|
@@ -158,6 +160,8 @@ struct nx_config_t {
|
|
* dynamic huffman */
|
|
struct selector mode; /** mode selector: selects between software
|
|
* and hardware compression. */
|
|
+ uint8_t virtualization; /** Indicate the virtualization type being
|
|
+ * used. */
|
|
};
|
|
typedef struct nx_config_t *nx_configp_t;
|
|
extern struct nx_config_t nx_config;
|
|
|
|
From b22eb7bffe61e36f70661921a689e44370d3c7e5 Mon Sep 17 00:00:00 2001
|
|
From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
Date: Thu, 24 Mar 2022 18:03:28 -0300
|
|
Subject: [PATCH 2/6] inflate: Move code that initializes the DDE to their own
|
|
functions
|
|
|
|
Create functions nx_reset_dde() and nx_init_dde() based on previous code
|
|
helping to reduce the size of nx_inflate_() and making it easier to
|
|
understand the code.
|
|
|
|
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
---
|
|
lib/nx_inflate.c | 197 ++++++++++++++++++++++++++++-------------------
|
|
1 file changed, 116 insertions(+), 81 deletions(-)
|
|
|
|
diff --git a/lib/nx_inflate.c b/lib/nx_inflate.c
|
|
index 77ad33c..f1d9adb 100644
|
|
--- a/lib/nx_inflate.c
|
|
+++ b/lib/nx_inflate.c
|
|
@@ -934,6 +934,120 @@ static int copy_data_to_fifo_in(nx_streamp s) {
|
|
return Z_OK;
|
|
}
|
|
|
|
+/** \brief Reset DDE to initial values.
|
|
+ *
|
|
+ * @param s nx_streamp to be processed.
|
|
+ * @return Function code as passed to CRB. The function will set the CRB and
|
|
+ * return the value here.
|
|
+ */
|
|
+static int nx_reset_dde(nx_streamp s) {
|
|
+ nx_gzip_crb_cpb_t *cmdp = s->nxcmdp;
|
|
+ uint32_t fc;
|
|
+
|
|
+ /* address/len lists */
|
|
+ clearp_dde(s->ddl_in);
|
|
+ clearp_dde(s->ddl_out);
|
|
+
|
|
+ /* FC, CRC, HistLen, Table 6-6 */
|
|
+ if (s->resuming || (s->dict_len > 0)) {
|
|
+ /* Resuming a partially decompressed input. */
|
|
+ fc = GZIP_FC_DECOMPRESS_RESUME;
|
|
+ } else {
|
|
+ /* First decompress job */
|
|
+ fc = GZIP_FC_DECOMPRESS;
|
|
+
|
|
+ /* We use the most recently measured compression ratio
|
|
+ as a heuristic to estimate the input and output
|
|
+ sizes. If we give too much input, the target buffer
|
|
+ overflows and NX cycles are wasted, and then we
|
|
+ must retry with smaller input size. 1000 is 100% */
|
|
+ s->last_comp_ratio = 1000UL;
|
|
+ }
|
|
+
|
|
+ /* clear then copy fc to the crb */
|
|
+ cmdp->crb.gzip_fc = 0;
|
|
+ putnn(cmdp->crb, gzip_fc, fc);
|
|
+
|
|
+ return fc;
|
|
+}
|
|
+
|
|
+/** \brief Initialize DDE, appending a dictionary, if necessary.
|
|
+ *
|
|
+ * @param s nx_streamp to be processed.
|
|
+ * @return The history length
|
|
+ */
|
|
+static int nx_init_dde(nx_streamp s) {
|
|
+ nx_gzip_crb_cpb_t *cmdp = s->nxcmdp;
|
|
+ int nx_history_len = s->history_len;
|
|
+
|
|
+ /* FC, CRC, HistLen, Table 6-6 */
|
|
+ if (s->resuming || (s->dict_len > 0)) {
|
|
+ /* Resuming a partially decompressed input. The key
|
|
+ to resume is supplying the max 32KB dictionary
|
|
+ (history) to NX, which is basically the last 32KB
|
|
+ or less of the output earlier produced. And also
|
|
+ make sure partial checksums are carried forward
|
|
+ */
|
|
+
|
|
+ /* Crc of prev job passed to the job to be resumed */
|
|
+ put32(cmdp->cpb, in_crc, s->crc32);
|
|
+ put32(cmdp->cpb, in_adler, s->adler32);
|
|
+
|
|
+ /* Round up the sizes to quadword. Section 2.10
|
|
+ Rounding up will not segfault because
|
|
+ nx_alloc_buffer has padding at the beginning */
|
|
+
|
|
+ if (s->dict_len > 0) {
|
|
+ /* lays dict on top of hist */
|
|
+ nx_history_len = nx_amend_history_with_dict(s);
|
|
+
|
|
+ if (s->wrap == HEADER_ZLIB) {
|
|
+ /* in the raw mode pass crc as is; in the zlib
|
|
+ mode initialize them */
|
|
+ put32(cmdp->cpb, in_crc, INIT_CRC );
|
|
+ put32(cmdp->cpb, in_adler, INIT_ADLER);
|
|
+ put32(cmdp->cpb, out_crc, INIT_CRC );
|
|
+ put32(cmdp->cpb, out_adler, INIT_ADLER);
|
|
+ }
|
|
+ print_dbg_info(s, __LINE__);
|
|
+ } else {
|
|
+ /* no dictionary here */
|
|
+ ASSERT( s->dict_len == 0 );
|
|
+ nx_history_len = (nx_history_len + NXQWSZ - 1) / NXQWSZ;
|
|
+ putnn(cmdp->cpb, in_histlen, nx_history_len);
|
|
+ /* convert to bytes */
|
|
+ nx_history_len = nx_history_len * NXQWSZ;
|
|
+
|
|
+ if (nx_history_len > 0) {
|
|
+ /* deflate history goes in first */
|
|
+ ASSERT(s->cur_out >= nx_history_len);
|
|
+ nx_append_dde(s->ddl_in,
|
|
+ s->fifo_out + (s->cur_out
|
|
+ - nx_history_len),
|
|
+ nx_history_len);
|
|
+ }
|
|
+ print_dbg_info(s, __LINE__);
|
|
+ }
|
|
+ } else {
|
|
+ nx_history_len = s->history_len = 0;
|
|
+ /* writing a 0 clears out subc as well */
|
|
+ cmdp->cpb.in_histlen = 0;
|
|
+
|
|
+ /* initialize the crc values */
|
|
+ put32(cmdp->cpb, in_crc, INIT_CRC );
|
|
+ put32(cmdp->cpb, in_adler, INIT_ADLER);
|
|
+ put32(cmdp->cpb, out_crc, INIT_CRC );
|
|
+ put32(cmdp->cpb, out_adler, INIT_ADLER);
|
|
+ }
|
|
+
|
|
+ /* We use the most recently measured compression ratio as a heuristic
|
|
+ to estimate the input and output sizes. If we give too much input,
|
|
+ the target buffer overflows and NX cycles are wasted, and then we
|
|
+ must retry with smaller input size. 1000 is 100% */
|
|
+ s->last_comp_ratio = NX_MAX(NX_MIN(1000UL, s->last_comp_ratio), 100L);
|
|
+ return nx_history_len;
|
|
+}
|
|
+
|
|
/** \brief Internal implementation of inflate.
|
|
*
|
|
* @param s nx_streamp to be processed.
|
|
@@ -1075,87 +1189,8 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
|
|
/* NX decompresses input data */
|
|
|
|
- /* address/len lists */
|
|
- clearp_dde(ddl_in);
|
|
- clearp_dde(ddl_out);
|
|
-
|
|
- nx_history_len = s->history_len;
|
|
-
|
|
- /* FC, CRC, HistLen, Table 6-6 */
|
|
- if (s->resuming || (s->dict_len > 0)) {
|
|
- /* Resuming a partially decompressed input. The key
|
|
- to resume is supplying the max 32KB dictionary
|
|
- (history) to NX, which is basically the last 32KB
|
|
- or less of the output earlier produced. And also
|
|
- make sure partial checksums are carried forward
|
|
- */
|
|
- fc = GZIP_FC_DECOMPRESS_RESUME;
|
|
-
|
|
- /* Crc of prev job passed to the job to be resumed */
|
|
- put32(cmdp->cpb, in_crc, s->crc32);
|
|
- put32(cmdp->cpb, in_adler, s->adler32);
|
|
-
|
|
- /* Round up the sizes to quadword. Section 2.10
|
|
- Rounding up will not segfault because
|
|
- nx_alloc_buffer has padding at the beginning */
|
|
-
|
|
- if (s->dict_len > 0) {
|
|
- /* lays dict on top of hist */
|
|
- nx_history_len = nx_amend_history_with_dict(s);
|
|
-
|
|
- if (s->wrap == HEADER_ZLIB) {
|
|
- /* in the raw mode pass crc as is; in the zlib mode
|
|
- initialize them */
|
|
- put32(cmdp->cpb, in_crc, INIT_CRC );
|
|
- put32(cmdp->cpb, in_adler, INIT_ADLER);
|
|
- put32(cmdp->cpb, out_crc, INIT_CRC );
|
|
- put32(cmdp->cpb, out_adler, INIT_ADLER);
|
|
- }
|
|
-
|
|
- s->last_comp_ratio = NX_MAX( NX_MIN(1000UL, s->last_comp_ratio), 100L );
|
|
-
|
|
- print_dbg_info(s, __LINE__);
|
|
- }
|
|
- else {
|
|
- /* no dictionary here */
|
|
- ASSERT( s->dict_len == 0 );
|
|
- nx_history_len = (nx_history_len + NXQWSZ - 1) / NXQWSZ;
|
|
- putnn(cmdp->cpb, in_histlen, nx_history_len);
|
|
- nx_history_len = nx_history_len * NXQWSZ; /* convert to bytes */
|
|
-
|
|
- if (nx_history_len > 0) {
|
|
- /* deflate history goes in first */
|
|
- ASSERT(s->cur_out >= nx_history_len);
|
|
- nx_append_dde(ddl_in, s->fifo_out + (s->cur_out - nx_history_len), nx_history_len);
|
|
- }
|
|
- print_dbg_info(s, __LINE__);
|
|
- }
|
|
- }
|
|
- else {
|
|
- /* First decompress job */
|
|
- fc = GZIP_FC_DECOMPRESS;
|
|
-
|
|
- nx_history_len = s->history_len = 0;
|
|
- /* writing a 0 clears out subc as well */
|
|
- cmdp->cpb.in_histlen = 0;
|
|
-
|
|
- /* initialize the crc values */
|
|
- put32(cmdp->cpb, in_crc, INIT_CRC );
|
|
- put32(cmdp->cpb, in_adler, INIT_ADLER);
|
|
- put32(cmdp->cpb, out_crc, INIT_CRC );
|
|
- put32(cmdp->cpb, out_adler, INIT_ADLER);
|
|
-
|
|
- /* We use the most recently measured compression ratio
|
|
- as a heuristic to estimate the input and output
|
|
- sizes. If we give too much input, the target buffer
|
|
- overflows and NX cycles are wasted, and then we
|
|
- must retry with smaller input size. 1000 is 100% */
|
|
- s->last_comp_ratio = 1000UL;
|
|
- }
|
|
-
|
|
- /* clear then copy fc to the crb */
|
|
- cmdp->crb.gzip_fc = 0;
|
|
- putnn(cmdp->crb, gzip_fc, fc);
|
|
+ fc = nx_reset_dde(s);
|
|
+ nx_history_len = nx_init_dde(s);
|
|
|
|
/*
|
|
* NX source buffers
|
|
|
|
From e376d92fa704108f1258e3a41fc1ffcf551d1c5b Mon Sep 17 00:00:00 2001
|
|
From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
Date: Fri, 25 Mar 2022 09:57:32 -0300
|
|
Subject: [PATCH 3/6] Fix the total amount of pages being touched
|
|
|
|
Fix and error in nx_touch_pages_dde() that was causing the function to
|
|
touch a different number of pages than requested.
|
|
|
|
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
---
|
|
lib/nx_zlib.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/lib/nx_zlib.c b/lib/nx_zlib.c
|
|
index a50d6f7..bf2a6fc 100644
|
|
--- a/lib/nx_zlib.c
|
|
+++ b/lib/nx_zlib.c
|
|
@@ -398,7 +398,7 @@ int nx_touch_pages_dde(nx_dde_t *ddep, long buf_sz, long page_sz, int wr)
|
|
|
|
/* touching fewer pages than encoded in the ddebc */
|
|
if ( total > buf_sz) {
|
|
- buf_len = NX_MIN(buf_len, total - buf_sz);
|
|
+ buf_len = buf_sz - (total - buf_len);
|
|
nx_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
|
|
prt_trace("touch loop break len 0x%x ddead %p\n", buf_len, (void *)buf_addr);
|
|
break;
|
|
|
|
From 1f3dc128a476c9bbbb1b503d2fc8f54365101ebf Mon Sep 17 00:00:00 2001
|
|
From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
Date: Thu, 24 Mar 2022 18:18:34 -0300
|
|
Subject: [PATCH 4/6] inflate: Move code that sets the DDE
|
|
|
|
Create functions nx_set_dde_in() and nx_set_dde_out() based on old code.
|
|
|
|
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
---
|
|
lib/nx_inflate.c | 64 +++++++++++++++++++++++++++++++++---------------
|
|
1 file changed, 44 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/lib/nx_inflate.c b/lib/nx_inflate.c
|
|
index f1d9adb..a9671b2 100644
|
|
--- a/lib/nx_inflate.c
|
|
+++ b/lib/nx_inflate.c
|
|
@@ -1048,6 +1048,41 @@ static int nx_init_dde(nx_streamp s) {
|
|
return nx_history_len;
|
|
}
|
|
|
|
+/** \brief Append input data to DDE
|
|
+ *
|
|
+ * @param s nx_streamp to be processed.
|
|
+ *
|
|
+ * @return The total amount of bytes appended to DDE
|
|
+ */
|
|
+static uint32_t nx_set_dde_in(nx_streamp s) {
|
|
+ /* Buffered user input is next */
|
|
+ if (s->fifo_in != NULL)
|
|
+ nx_append_dde(s->ddl_in, s->fifo_in + s->cur_in, s->used_in);
|
|
+ /* Then current user input. */
|
|
+ nx_append_dde(s->ddl_in, s->next_in, s->avail_in);
|
|
+ /* Total bytes going in to engine. */
|
|
+ return getp32(s->ddl_in, ddebc);
|
|
+}
|
|
+
|
|
+/** \brief Append output data to DDE
|
|
+ *
|
|
+ * @param s nx_streamp to be processed.
|
|
+ *
|
|
+ * @return The total amount of bytes appended to DDE
|
|
+ */
|
|
+static uint32_t nx_set_dde_out(nx_streamp s) {
|
|
+ /* Decompress to user buffer first. */
|
|
+ nx_append_dde(s->ddl_out, s->next_out, s->avail_out);
|
|
+
|
|
+ /* Overflow to fifo_out.
|
|
+ used_out == 0 required by definition. */
|
|
+ ASSERT(s->used_out == 0);
|
|
+ nx_append_dde(s->ddl_out, s->fifo_out + s->cur_out,
|
|
+ s->len_out - s->cur_out);
|
|
+
|
|
+ return s->avail_out + s->len_out - s->cur_out;
|
|
+}
|
|
+
|
|
/** \brief Internal implementation of inflate.
|
|
*
|
|
* @param s nx_streamp to be processed.
|
|
@@ -1195,28 +1230,13 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
/*
|
|
* NX source buffers
|
|
*/
|
|
- /* buffered user input is next */
|
|
- if (s->fifo_in != NULL)
|
|
- nx_append_dde(ddl_in, s->fifo_in + s->cur_in, s->used_in);
|
|
- /* then current user input */
|
|
- nx_append_dde(ddl_in, s->next_in, s->avail_in);
|
|
- source_sz = getp32(ddl_in, ddebc); /* total bytes going in to engine */
|
|
- ASSERT( source_sz > nx_history_len );
|
|
+ source_sz = nx_set_dde_in(s);
|
|
+ ASSERT(source_sz > nx_history_len);
|
|
|
|
/*
|
|
* NX target buffers
|
|
*/
|
|
- ASSERT(s->used_out == 0);
|
|
-
|
|
- uint32_t len_next_out = s->avail_out;
|
|
- nx_append_dde(ddl_out, s->next_out, len_next_out); /* decomp in to user buffer */
|
|
-
|
|
- /* overflow, used_out == 0 required by definition, +used_out below is unnecessary */
|
|
- nx_append_dde(ddl_out, s->fifo_out + s->cur_out + s->used_out, s->len_out - s->cur_out - s->used_out);
|
|
- target_sz = len_next_out + s->len_out - s->cur_out - s->used_out;
|
|
-
|
|
- prt_info("len_next_out %d len_out %d cur_out %d used_out %d source_sz %d history_len %d\n",
|
|
- len_next_out, s->len_out, s->cur_out, s->used_out, source_sz, nx_history_len);
|
|
+ target_sz = nx_set_dde_out(s);
|
|
|
|
/* We want exactly the History size amount of 32KB to overflow
|
|
in to fifo_out. If overflow is less, the history spans
|
|
@@ -1228,6 +1248,7 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
these copies (memcpy) for performance. Therefore, the
|
|
heuristic here will estimate the source size for the
|
|
desired target size */
|
|
+ uint32_t len_next_out = s->avail_out;
|
|
|
|
/* avail_out plus 32 KB history plus a bit of overhead */
|
|
uint32_t target_sz_expected = len_next_out + INF_HIS_LEN + (INF_HIS_LEN >> 2);
|
|
@@ -1240,11 +1261,14 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
|
|
prt_info("target_sz_expected %d source_sz_expected %d source_sz %d last_comp_ratio %d nx_history_len %d\n", target_sz_expected, source_sz_expected, source_sz, s->last_comp_ratio, nx_history_len);
|
|
|
|
+ prt_info("%s:%d len_next_out %d len_out %d cur_out %d"
|
|
+ " used_out %d source_sz %d history_len %d\n",
|
|
+ __FUNCTION__, __LINE__, len_next_out, s->len_out, s->cur_out,
|
|
+ s->used_out, source_sz, nx_history_len);
|
|
+
|
|
/* do not include input side history in the estimation */
|
|
source_sz = source_sz - nx_history_len;
|
|
-
|
|
ASSERT(source_sz > 0);
|
|
-
|
|
source_sz = NX_MIN(source_sz, source_sz_expected);
|
|
|
|
/* add the history back */
|
|
|
|
From eb6cb7b01fe1fa337979353e905e3ad96514b233 Mon Sep 17 00:00:00 2001
|
|
From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
Date: Thu, 24 Mar 2022 18:37:27 -0300
|
|
Subject: [PATCH 5/6] inflate: cosmetic improvements
|
|
|
|
- Add source code comments.
|
|
- Improve indentation.
|
|
- Break long lines.
|
|
- Fix error and information messages.
|
|
|
|
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
---
|
|
lib/nx_inflate.c | 51 ++++++++++++++++++++++++++++++++++++------------
|
|
1 file changed, 38 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/lib/nx_inflate.c b/lib/nx_inflate.c
|
|
index a9671b2..a6070bd 100644
|
|
--- a/lib/nx_inflate.c
|
|
+++ b/lib/nx_inflate.c
|
|
@@ -1090,14 +1090,31 @@ static uint32_t nx_set_dde_out(nx_streamp s) {
|
|
*/
|
|
static int nx_inflate_(nx_streamp s, int flush)
|
|
{
|
|
- /* queuing, file ops, byte counting */
|
|
- uint32_t write_sz, source_sz, target_sz;
|
|
+ /** \brief Sum of the bytes that may be used by NX as input
|
|
+ *
|
|
+ * Total amount of bytes sent to the NX to be used as input,
|
|
+ * i.e. sum of the bytes in next_in and fifo_in. */
|
|
+ uint32_t source_sz;
|
|
+
|
|
+ /** \brief Sum of the bytes that may be used by NX as output
|
|
+ *
|
|
+ * Maximum amount of bytes available by the NX to be used as output,
|
|
+ * i.e. sum of the bytes available in next_out and fifo_out. */
|
|
+ uint32_t target_sz;
|
|
+
|
|
+ uint32_t write_sz;
|
|
long loop_cnt = 0, loop_max = 0xffff;
|
|
|
|
/** \brief inflate benefits from large jobs; memcopies must be
|
|
* amortized. */
|
|
const uint32_t inflate_per_job_len = nx_config.per_job_len;
|
|
|
|
+ /** \brief Estimated value for target_sz. Used to calculate
|
|
+ * source_sz_expected. */
|
|
+ uint32_t target_sz_expected;
|
|
+ /** \brief Estimated value for source_sz. */
|
|
+ uint32_t source_sz_expected;
|
|
+
|
|
/* nx hardware */
|
|
uint32_t sfbt = 0, subc = 0, spbc, tpbc, nx_ce, fc;
|
|
|
|
@@ -1251,16 +1268,20 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
uint32_t len_next_out = s->avail_out;
|
|
|
|
/* avail_out plus 32 KB history plus a bit of overhead */
|
|
- uint32_t target_sz_expected = len_next_out + INF_HIS_LEN + (INF_HIS_LEN >> 2);
|
|
+ target_sz_expected = len_next_out + INF_HIS_LEN + (INF_HIS_LEN >> 2);
|
|
|
|
target_sz_expected = NX_MIN(target_sz_expected, inflate_per_job_len);
|
|
|
|
/* e.g. if we want 100KB at the output and if the compression
|
|
ratio is 10% we want 10KB if input */
|
|
- uint32_t source_sz_expected = (uint32_t)(((uint64_t)target_sz_expected * s->last_comp_ratio + 1000L)/1000UL);
|
|
+ source_sz_expected = (uint32_t) (((uint64_t) target_sz_expected
|
|
+ * s->last_comp_ratio + 1000L)/1000UL);
|
|
|
|
- prt_info("target_sz_expected %d source_sz_expected %d source_sz %d last_comp_ratio %d nx_history_len %d\n", target_sz_expected, source_sz_expected, source_sz, s->last_comp_ratio, nx_history_len);
|
|
|
|
+ prt_info("%s:%d target_sz_expected %d source_sz_expected %d"
|
|
+ " source_sz %d last_comp_ratio %d nx_history_len %d\n",
|
|
+ __FUNCTION__, __LINE__, target_sz_expected, source_sz_expected,
|
|
+ source_sz, s->last_comp_ratio, nx_history_len);
|
|
prt_info("%s:%d len_next_out %d len_out %d cur_out %d"
|
|
" used_out %d source_sz %d history_len %d\n",
|
|
__FUNCTION__, __LINE__, len_next_out, s->len_out, s->cur_out,
|
|
@@ -1280,8 +1301,11 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
|
|
/* fault in pages */
|
|
nx_touch_pages_dde(ddl_in, source_sz, nx_config.page_sz, 0);
|
|
- nx_touch_pages_dde(ddl_out, target_sz, nx_config.page_sz, 1);
|
|
- nx_touch_pages( (void *)cmdp, sizeof(nx_gzip_crb_cpb_t), nx_config.page_sz, 0);
|
|
+ nx_touch_pages_dde(ddl_out,
|
|
+ target_sz,
|
|
+ nx_config.page_sz, 1);
|
|
+ nx_touch_pages((void *) cmdp, sizeof(nx_gzip_crb_cpb_t),
|
|
+ nx_config.page_sz, 0);
|
|
|
|
/*
|
|
* send job to NX
|
|
@@ -1298,9 +1322,9 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
faulting address to fsaddr */
|
|
print_dbg_info(s, __LINE__);
|
|
|
|
- prt_warn("ERR_NX_AT_FAULT: crb.csb.fsaddr %p source_sz %d ",
|
|
- (void *)cmdp->crb.csb.fsaddr, source_sz);
|
|
- prt_warn("target_sz %d\n", target_sz);
|
|
+ prt_warn("ERR_NX_AT_FAULT: crb.csb.fsaddr %p source_sz %d "
|
|
+ "target_sz %d\n", (void *)cmdp->crb.csb.fsaddr,
|
|
+ source_sz, target_sz);
|
|
#ifdef NX_LOG_SOURCE_TARGET
|
|
nx_print_dde(ddl_in, "source");
|
|
nx_print_dde(ddl_out, "target");
|
|
@@ -1339,8 +1363,8 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
if (ticks_total > (timeout_pgfaults * nx_get_freq())) {
|
|
/* TODO what to do when page faults are too many?
|
|
* Kernel MM would have killed the process. */
|
|
- prt_err("Cannot make progress; too many page");
|
|
- prt_err(" faults cc= %d\n", cc);
|
|
+ prt_err("Cannot make progress; too many page"
|
|
+ " faults cc= %d\n", cc);
|
|
}
|
|
else {
|
|
prt_warn("ERR_NX_AT_FAULT: more retry\n");
|
|
@@ -1397,7 +1421,8 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
cover the max expansion of INF_MIN_INPUT_LEN
|
|
bytes */
|
|
|
|
- prt_info("ERR_NX_TARGET_SPACE; retry with smaller input data src %d hist %d\n", source_sz, nx_history_len);
|
|
+ prt_info("ERR_NX_TARGET_SPACE; retry with smaller input data"
|
|
+ " src %d hist %d\n", source_sz, nx_history_len);
|
|
goto restart_nx;
|
|
|
|
case ERR_NX_OK:
|
|
|
|
From 806bf8e3ed1d0ae8a21bc6b2035df390f1062c26 Mon Sep 17 00:00:00 2001
|
|
From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
Date: Mon, 28 Mar 2022 18:15:37 -0300
|
|
Subject: [PATCH 6/6] inflate: Limit the amount of data added to the DDE
|
|
|
|
Stop adding all input and output data to the DDE and limit based on the
|
|
calculated value for source_sz_expected and target_sz_expected.
|
|
By limiting these values, we end up better estimating the amount of
|
|
pages that need to be touched, reducing the amount of time spent
|
|
touching pages that might not be used.
|
|
|
|
Reported-by: Puvichakravarthy Ramachandran <puvichakravarthy@in.ibm.com>
|
|
Reported-by: Poorna Chandra Vemula <Poorna.Chandra.Vemula@ibm.com>
|
|
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
---
|
|
lib/nx_inflate.c | 180 +++++++++++++++++++++++++++++------------------
|
|
1 file changed, 111 insertions(+), 69 deletions(-)
|
|
|
|
diff --git a/lib/nx_inflate.c b/lib/nx_inflate.c
|
|
index a6070bd..b30cdf6 100644
|
|
--- a/lib/nx_inflate.c
|
|
+++ b/lib/nx_inflate.c
|
|
@@ -955,13 +955,6 @@ static int nx_reset_dde(nx_streamp s) {
|
|
} else {
|
|
/* First decompress job */
|
|
fc = GZIP_FC_DECOMPRESS;
|
|
-
|
|
- /* We use the most recently measured compression ratio
|
|
- as a heuristic to estimate the input and output
|
|
- sizes. If we give too much input, the target buffer
|
|
- overflows and NX cycles are wasted, and then we
|
|
- must retry with smaller input size. 1000 is 100% */
|
|
- s->last_comp_ratio = 1000UL;
|
|
}
|
|
|
|
/* clear then copy fc to the crb */
|
|
@@ -1051,15 +1044,24 @@ static int nx_init_dde(nx_streamp s) {
|
|
/** \brief Append input data to DDE
|
|
*
|
|
* @param s nx_streamp to be processed.
|
|
+ * @param source_sz_expected The total amount of bytes expected as input. It
|
|
+ * does not include dictionary or history.
|
|
*
|
|
* @return The total amount of bytes appended to DDE
|
|
*/
|
|
-static uint32_t nx_set_dde_in(nx_streamp s) {
|
|
+static uint32_t nx_set_dde_in(nx_streamp s, uint32_t source_sz_expected) {
|
|
+ uint32_t tmp = 0;
|
|
+
|
|
/* Buffered user input is next */
|
|
- if (s->fifo_in != NULL)
|
|
- nx_append_dde(s->ddl_in, s->fifo_in + s->cur_in, s->used_in);
|
|
- /* Then current user input. */
|
|
- nx_append_dde(s->ddl_in, s->next_in, s->avail_in);
|
|
+ if (s->fifo_in != NULL) {
|
|
+ tmp = NX_MIN(s->used_in, source_sz_expected);
|
|
+ nx_append_dde(s->ddl_in, s->fifo_in + s->cur_in, tmp);
|
|
+ }
|
|
+ if (tmp < source_sz_expected) {
|
|
+ tmp = NX_MIN(s->avail_in, source_sz_expected - tmp);
|
|
+ /* Then current user input. */
|
|
+ nx_append_dde(s->ddl_in, s->next_in, tmp);
|
|
+ }
|
|
/* Total bytes going in to engine. */
|
|
return getp32(s->ddl_in, ddebc);
|
|
}
|
|
@@ -1067,20 +1069,32 @@ static uint32_t nx_set_dde_in(nx_streamp s) {
|
|
/** \brief Append output data to DDE
|
|
*
|
|
* @param s nx_streamp to be processed.
|
|
+ * @param target_sz_expected The total amount of bytes expected as output.
|
|
*
|
|
* @return The total amount of bytes appended to DDE
|
|
*/
|
|
-static uint32_t nx_set_dde_out(nx_streamp s) {
|
|
+static uint32_t nx_set_dde_out(nx_streamp s, uint32_t target_sz_expected) {
|
|
+ uint32_t tmp;
|
|
+ uint32_t ret;
|
|
+
|
|
+ ret = NX_MIN(s->avail_out, target_sz_expected);
|
|
+
|
|
/* Decompress to user buffer first. */
|
|
- nx_append_dde(s->ddl_out, s->next_out, s->avail_out);
|
|
+ nx_append_dde(s->ddl_out, s->next_out, ret);
|
|
+
|
|
+ if (ret < target_sz_expected) {
|
|
+ tmp = NX_MIN(s->len_out - s->cur_out,
|
|
+ target_sz_expected - ret);
|
|
+
|
|
+ /* Overflow to fifo_out.
|
|
+ used_out == 0 required by definition. */
|
|
+ ASSERT(s->used_out == 0);
|
|
+ nx_append_dde(s->ddl_out, s->fifo_out + s->cur_out, tmp);
|
|
|
|
- /* Overflow to fifo_out.
|
|
- used_out == 0 required by definition. */
|
|
- ASSERT(s->used_out == 0);
|
|
- nx_append_dde(s->ddl_out, s->fifo_out + s->cur_out,
|
|
- s->len_out - s->cur_out);
|
|
+ ret += tmp;
|
|
+ }
|
|
|
|
- return s->avail_out + s->len_out - s->cur_out;
|
|
+ return ret;
|
|
}
|
|
|
|
/** \brief Internal implementation of inflate.
|
|
@@ -1094,7 +1108,7 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
*
|
|
* Total amount of bytes sent to the NX to be used as input,
|
|
* i.e. sum of the bytes in next_in and fifo_in. */
|
|
- uint32_t source_sz;
|
|
+ uint32_t source_sz = 0;
|
|
|
|
/** \brief Sum of the bytes that may be used by NX as output
|
|
*
|
|
@@ -1242,46 +1256,69 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
/* NX decompresses input data */
|
|
|
|
fc = nx_reset_dde(s);
|
|
- nx_history_len = nx_init_dde(s);
|
|
|
|
- /*
|
|
- * NX source buffers
|
|
- */
|
|
- source_sz = nx_set_dde_in(s);
|
|
- ASSERT(source_sz > nx_history_len);
|
|
+ /** Estimate the amount of data sent to the NX. Ideally, we want
|
|
+ * exactly the history size amount of 32 KiB to overflow in to fifo_out
|
|
+ * in order to minimize copies of memory.
|
|
+ * If overflow is less than 32 KiB, the history spans next_out and
|
|
+ * fifo_out and must be copied in to fifo_out to setup history for the
|
|
+ * next job. The fifo_out fraction is also copied back to user's
|
|
+ * next_out before the next job.
|
|
+ * If overflow is more, all the overflow must be copied back
|
|
+ * to user's next_out before the next job.
|
|
+ * If overflow is much more, we may get an ERR_NX_TARGET_SPACE, forcing
|
|
+ * us to reduce the source before trying again. A retry in this case
|
|
+ * will probably require NX to process much more than 32 KiB, which
|
|
+ * requires more time than copying 32 KiB of data.
|
|
+ *
|
|
+ * With that said, we want to minimize unecessary work (i.e. memcpy
|
|
+ * and retrying NX jobs) for performance. Therefore, the heuristic
|
|
+ * here will estimate the source size for the desired target size, but
|
|
+ * it prioritizes avoiding ERR_NX_TARGET_SPACE. */
|
|
|
|
- /*
|
|
- * NX target buffers
|
|
- */
|
|
- target_sz = nx_set_dde_out(s);
|
|
-
|
|
- /* We want exactly the History size amount of 32KB to overflow
|
|
- in to fifo_out. If overflow is less, the history spans
|
|
- next_out and fifo_out and must be copied in to fifo_out to
|
|
- setup history for the next job, and the fifo_out fraction is
|
|
- also copied back to user's next_out before the next job.
|
|
- If overflow is more, all the overflow must be copied back
|
|
- to user's next_out before the next job. We want to minimize
|
|
- these copies (memcpy) for performance. Therefore, the
|
|
- heuristic here will estimate the source size for the
|
|
- desired target size */
|
|
uint32_t len_next_out = s->avail_out;
|
|
+ s->last_comp_ratio = NX_MAX(NX_MIN(1000UL, s->last_comp_ratio), 100L);
|
|
|
|
- /* avail_out plus 32 KB history plus a bit of overhead */
|
|
+ /* avail_out plus 32 KiB history plus a bit of overhead */
|
|
target_sz_expected = len_next_out + INF_HIS_LEN + (INF_HIS_LEN >> 2);
|
|
-
|
|
target_sz_expected = NX_MIN(target_sz_expected, inflate_per_job_len);
|
|
|
|
- /* e.g. if we want 100KB at the output and if the compression
|
|
- ratio is 10% we want 10KB if input */
|
|
+ /** Calculate source_sz_expected based on target_sz_expected and the
|
|
+ * last compression ratio, e.g. if we want 100KB at the output and if
|
|
+ * the compression ratio is 10% we want 10KB if input */
|
|
source_sz_expected = (uint32_t) (((uint64_t) target_sz_expected
|
|
* s->last_comp_ratio + 1000L)/1000UL);
|
|
|
|
+ /** After calculating source_sz_expected, try to provide extra
|
|
+ * target_sz_expected in order to avoid an ERR_NX_TARGET_SPACE. */
|
|
+ target_sz_expected = NX_MIN(len_next_out + INF_HIS_LEN + (INF_HIS_LEN >> 2),
|
|
+ 4 * inflate_per_job_len);
|
|
+ prt_info("%s:%d target_sz_expected %d source_sz_expected %d"
|
|
+ " source_sz %d last_comp_ratio %d\n",
|
|
+ __FUNCTION__, __LINE__, target_sz_expected, source_sz_expected,
|
|
+ source_sz, s->last_comp_ratio);
|
|
+
|
|
+
|
|
+init_dde:
|
|
+ nx_history_len = nx_init_dde(s);
|
|
+
|
|
+ /*
|
|
+ * NX source buffers
|
|
+ */
|
|
+ source_sz = nx_set_dde_in(s, source_sz_expected);
|
|
+ ASSERT(source_sz > nx_history_len);
|
|
+ ASSERT(source_sz <= source_sz_expected + nx_history_len);
|
|
|
|
prt_info("%s:%d target_sz_expected %d source_sz_expected %d"
|
|
" source_sz %d last_comp_ratio %d nx_history_len %d\n",
|
|
__FUNCTION__, __LINE__, target_sz_expected, source_sz_expected,
|
|
source_sz, s->last_comp_ratio, nx_history_len);
|
|
+
|
|
+ /*
|
|
+ * NX target buffers
|
|
+ */
|
|
+ target_sz = nx_set_dde_out(s, target_sz_expected);
|
|
+
|
|
prt_info("%s:%d len_next_out %d len_out %d cur_out %d"
|
|
" used_out %d source_sz %d history_len %d\n",
|
|
__FUNCTION__, __LINE__, len_next_out, s->len_out, s->cur_out,
|
|
@@ -1345,19 +1382,22 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
that is about 2 pages minimum for source and
|
|
and 6 pages for target; if the system does not
|
|
have 8 free pages then the loop will last forever */
|
|
- source_sz = source_sz - nx_history_len;
|
|
- if (source_sz > (2 * INF_MIN_INPUT_LEN))
|
|
- source_sz = (source_sz + 1) / 2;
|
|
- else if (source_sz > INF_MIN_INPUT_LEN)
|
|
- source_sz = INF_MIN_INPUT_LEN;
|
|
-
|
|
- /* else if caller gave fewer source bytes, keep it as is */
|
|
- source_sz = source_sz + nx_history_len;
|
|
-
|
|
- if (target_sz > (2 * INF_MAX_EXPANSION_BYTES))
|
|
- target_sz = (target_sz + 1) / 2;
|
|
- else if (target_sz > INF_MAX_EXPANSION_BYTES)
|
|
- target_sz = INF_MAX_EXPANSION_BYTES;
|
|
+ source_sz_expected = source_sz - nx_history_len;
|
|
+ if (source_sz_expected > (2 * INF_MIN_INPUT_LEN))
|
|
+ source_sz_expected
|
|
+ = (source_sz_expected + 1) / 2;
|
|
+ else if (source_sz_expected > INF_MIN_INPUT_LEN)
|
|
+ source_sz_expected = INF_MIN_INPUT_LEN;
|
|
+
|
|
+ /* else if caller gave fewer source bytes, keep it as
|
|
+ is. */
|
|
+ source_sz = source_sz_expected + nx_history_len;
|
|
+
|
|
+ if (target_sz_expected > (2 * INF_MAX_EXPANSION_BYTES))
|
|
+ target_sz_expected
|
|
+ = (target_sz_expected + 1) / 2;
|
|
+ else if (target_sz_expected > INF_MAX_EXPANSION_BYTES)
|
|
+ target_sz_expected = INF_MAX_EXPANSION_BYTES;
|
|
|
|
ticks_total = nx_wait_ticks(500, ticks_total, 0);
|
|
if (ticks_total > (timeout_pgfaults * nx_get_freq())) {
|
|
@@ -1368,7 +1408,8 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
}
|
|
else {
|
|
prt_warn("ERR_NX_AT_FAULT: more retry\n");
|
|
- goto restart_nx;
|
|
+ fc = nx_reset_dde(s);
|
|
+ goto init_dde;
|
|
}
|
|
}
|
|
|
|
@@ -1403,18 +1444,17 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
/* Target buffer not large enough; retry smaller input
|
|
data; give at least 1 byte. SPBC/TPBC are not valid */
|
|
ASSERT( source_sz > nx_history_len );
|
|
- source_sz = ((source_sz - nx_history_len + 1) / 2) + nx_history_len;
|
|
+ source_sz_expected = (source_sz - nx_history_len + 1) / 2;
|
|
|
|
- source_sz = source_sz - nx_history_len;
|
|
/* reduce large source down to minimum viable; if
|
|
source is already small don't change it */
|
|
- if (source_sz > (2 * INF_MIN_INPUT_LEN))
|
|
- source_sz = (source_sz + 1) / 2;
|
|
- else if (source_sz > INF_MIN_INPUT_LEN)
|
|
- source_sz = INF_MIN_INPUT_LEN;
|
|
+ if (source_sz_expected > (2 * INF_MIN_INPUT_LEN))
|
|
+ source_sz_expected = (source_sz_expected + 1) / 2;
|
|
+ else if (source_sz_expected > INF_MIN_INPUT_LEN)
|
|
+ source_sz_expected = INF_MIN_INPUT_LEN;
|
|
|
|
/* else if caller gave fewer source bytes, keep it as is */
|
|
- source_sz = source_sz + nx_history_len;
|
|
+ source_sz = source_sz_expected + nx_history_len;
|
|
|
|
/* do not change target size because we allocated a
|
|
minimum of INF_MAX_EXPANSION_BYTES which should
|
|
@@ -1422,8 +1462,10 @@ static int nx_inflate_(nx_streamp s, int flush)
|
|
bytes */
|
|
|
|
prt_info("ERR_NX_TARGET_SPACE; retry with smaller input data"
|
|
- " src %d hist %d\n", source_sz, nx_history_len);
|
|
- goto restart_nx;
|
|
+ " source_sz_expected %d nx_history_len %d\n",
|
|
+ source_sz_expected, nx_history_len);
|
|
+ fc = nx_reset_dde(s);
|
|
+ goto init_dde;
|
|
|
|
case ERR_NX_OK:
|
|
|