* [PATCH v4 0/2] PM: hibernate: make compression threads configurable and support dynamic crc arrays
@ 2025-10-14 7:14 Xueqin Luo
2025-10-14 7:14 ` [PATCH v4 1/2] PM: hibernate: dynamically allocate crc->unc_len/unc for configurable threads Xueqin Luo
2025-10-14 7:14 ` [PATCH v4 2/2] PM: hibernate: make compression threads configurable Xueqin Luo
0 siblings, 2 replies; 4+ messages in thread
From: Xueqin Luo @ 2025-10-14 7:14 UTC (permalink / raw)
To: rafael, pavel, lenb, linux-pm, linux-kernel; +Cc: Xueqin Luo
Hi,
This is v4 of the series to make hibernate compression/decompression
threads configurable and improve scalability.
Changes since v3:
* Only patch 2 was updated: When an invalid `cmp_threads` value is provided,
fall back to the default value (3).
Thanks for your feedback and review!
Xueqin Luo (2):
PM: hibernate: dynamically allocate crc->unc_len/unc for configurable
threads
PM: hibernate: make compression threads configurable
kernel/power/swap.c | 82 +++++++++++++++++++++++++++++++++++----------
1 file changed, 64 insertions(+), 18 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v4 1/2] PM: hibernate: dynamically allocate crc->unc_len/unc for configurable threads
2025-10-14 7:14 [PATCH v4 0/2] PM: hibernate: make compression threads configurable and support dynamic crc arrays Xueqin Luo
@ 2025-10-14 7:14 ` Xueqin Luo
2025-10-14 7:14 ` [PATCH v4 2/2] PM: hibernate: make compression threads configurable Xueqin Luo
1 sibling, 0 replies; 4+ messages in thread
From: Xueqin Luo @ 2025-10-14 7:14 UTC (permalink / raw)
To: rafael, pavel, lenb, linux-pm, linux-kernel; +Cc: Xueqin Luo
Convert crc->unc_len and crc->unc from fixed-size arrays to dynamically
allocated arrays, sized according to the actual number of threads selected
at runtime. This removes the fixed limit imposed by CMP_THREADS.
Signed-off-by: Xueqin Luo <luoxueqin@kylinos.cn>
---
kernel/power/swap.c | 58 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 44 insertions(+), 14 deletions(-)
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 0beff7eeaaba..f8c13f5672ec 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -585,10 +585,48 @@ struct crc_data {
wait_queue_head_t go; /* start crc update */
wait_queue_head_t done; /* crc update done */
u32 *crc32; /* points to handle's crc32 */
- size_t *unc_len[CMP_THREADS]; /* uncompressed lengths */
- unsigned char *unc[CMP_THREADS]; /* uncompressed data */
+ size_t **unc_len; /* uncompressed lengths */
+ unsigned char **unc; /* uncompressed data */
};
+static struct crc_data *alloc_crc_data(int nr_threads)
+{
+ struct crc_data *crc;
+
+ crc = kzalloc(sizeof(*crc), GFP_KERNEL);
+ if (!crc)
+ return NULL;
+
+ crc->unc = kcalloc(nr_threads, sizeof(*crc->unc), GFP_KERNEL);
+ if (!crc->unc)
+ goto err_free_crc;
+
+ crc->unc_len = kcalloc(nr_threads, sizeof(*crc->unc_len), GFP_KERNEL);
+ if (!crc->unc_len)
+ goto err_free_unc;
+
+ return crc;
+
+err_free_unc:
+ kfree(crc->unc);
+err_free_crc:
+ kfree(crc);
+ return NULL;
+}
+
+static void free_crc_data(struct crc_data *crc)
+{
+ if (!crc)
+ return;
+
+ if (crc->thr)
+ kthread_stop(crc->thr);
+
+ kfree(crc->unc_len);
+ kfree(crc->unc);
+ kfree(crc);
+}
+
/*
* CRC32 update function that runs in its own thread.
*/
@@ -719,7 +757,7 @@ static int save_compressed_image(struct swap_map_handle *handle,
goto out_clean;
}
- crc = kzalloc(sizeof(*crc), GFP_KERNEL);
+ crc = alloc_crc_data(nr_threads);
if (!crc) {
pr_err("Failed to allocate crc\n");
ret = -ENOMEM;
@@ -885,11 +923,7 @@ static int save_compressed_image(struct swap_map_handle *handle,
out_clean:
hib_finish_batch(&hb);
- if (crc) {
- if (crc->thr)
- kthread_stop(crc->thr);
- kfree(crc);
- }
+ free_crc_data(crc);
if (data) {
for (thr = 0; thr < nr_threads; thr++) {
if (data[thr].thr)
@@ -1239,7 +1273,7 @@ static int load_compressed_image(struct swap_map_handle *handle,
goto out_clean;
}
- crc = kzalloc(sizeof(*crc), GFP_KERNEL);
+ crc = alloc_crc_data(nr_threads);
if (!crc) {
pr_err("Failed to allocate crc\n");
ret = -ENOMEM;
@@ -1506,11 +1540,7 @@ static int load_compressed_image(struct swap_map_handle *handle,
hib_finish_batch(&hb);
for (i = 0; i < ring_size; i++)
free_page((unsigned long)page[i]);
- if (crc) {
- if (crc->thr)
- kthread_stop(crc->thr);
- kfree(crc);
- }
+ free_crc_data(crc);
if (data) {
for (thr = 0; thr < nr_threads; thr++) {
if (data[thr].thr)
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v4 2/2] PM: hibernate: make compression threads configurable
2025-10-14 7:14 [PATCH v4 0/2] PM: hibernate: make compression threads configurable and support dynamic crc arrays Xueqin Luo
2025-10-14 7:14 ` [PATCH v4 1/2] PM: hibernate: dynamically allocate crc->unc_len/unc for configurable threads Xueqin Luo
@ 2025-10-14 7:14 ` Xueqin Luo
2025-10-20 19:14 ` Rafael J. Wysocki
1 sibling, 1 reply; 4+ messages in thread
From: Xueqin Luo @ 2025-10-14 7:14 UTC (permalink / raw)
To: rafael, pavel, lenb, linux-pm, linux-kernel; +Cc: Xueqin Luo
The number of compression/decompression threads has a direct impact on
hibernate image generation and resume latency. Using more threads can
reduce overall resume time, but on systems with fewer CPU cores it may
also introduce contention and reduce efficiency.
Performance was evaluated on an 8-core ARM system, averaged over 10 runs:
cmp_threads hibernate time (s) resume time (s)
--------------------------------------------------
3 12.14 18.86
4 12.28 17.48
5 11.09 16.77
6 11.08 16.44
With 5–6 threads, resume latency improves by approximately 12% compared
to the default 3-thread configuration, with negligible impact on
hibernate time.
Introduce a new kernel parameter `cmp_threads=` that allows users and
integrators to tune the number of compression/decompression threads at
boot. This provides a way to balance performance and CPU utilization
across a wide range of hardware without recompiling the kernel.
Signed-off-by: Xueqin Luo <luoxueqin@kylinos.cn>
---
kernel/power/swap.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index f8c13f5672ec..540cf902498c 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -519,8 +519,8 @@ static int swap_writer_finish(struct swap_map_handle *handle,
CMP_HEADER, PAGE_SIZE)
#define CMP_SIZE (CMP_PAGES * PAGE_SIZE)
-/* Maximum number of threads for compression/decompression. */
-#define CMP_THREADS 3
+/* Default number of threads for compression/decompression. */
+static int cmp_threads = 3;
/* Minimum/maximum number of pages for read buffering. */
#define CMP_MIN_RD_PAGES 1024
@@ -741,7 +741,7 @@ static int save_compressed_image(struct swap_map_handle *handle,
* footprint.
*/
nr_threads = num_online_cpus() - 1;
- nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
+ nr_threads = clamp_val(nr_threads, 1, cmp_threads);
page = (void *)__get_free_page(GFP_NOIO | __GFP_HIGH);
if (!page) {
@@ -1257,7 +1257,7 @@ static int load_compressed_image(struct swap_map_handle *handle,
* footprint.
*/
nr_threads = num_online_cpus() - 1;
- nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
+ nr_threads = clamp_val(nr_threads, 1, cmp_threads);
page = vmalloc_array(CMP_MAX_RD_PAGES, sizeof(*page));
if (!page) {
@@ -1697,3 +1697,19 @@ static int __init swsusp_header_init(void)
}
core_initcall(swsusp_header_init);
+
+static int __init cmp_threads_setup(char *str)
+{
+ int rc = kstrtouint(str, 0, &cmp_threads);
+
+ if (rc)
+ return rc;
+
+ if (cmp_threads < 1)
+ cmp_threads = 3;
+
+ return 1;
+
+}
+
+__setup("cmp_threads=", cmp_threads_setup);
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v4 2/2] PM: hibernate: make compression threads configurable
2025-10-14 7:14 ` [PATCH v4 2/2] PM: hibernate: make compression threads configurable Xueqin Luo
@ 2025-10-20 19:14 ` Rafael J. Wysocki
0 siblings, 0 replies; 4+ messages in thread
From: Rafael J. Wysocki @ 2025-10-20 19:14 UTC (permalink / raw)
To: Xueqin Luo; +Cc: rafael, pavel, lenb, linux-pm, linux-kernel
On Tue, Oct 14, 2025 at 9:20 AM Xueqin Luo <luoxueqin@kylinos.cn> wrote:
>
> The number of compression/decompression threads has a direct impact on
> hibernate image generation and resume latency. Using more threads can
> reduce overall resume time, but on systems with fewer CPU cores it may
> also introduce contention and reduce efficiency.
>
> Performance was evaluated on an 8-core ARM system, averaged over 10 runs:
>
> cmp_threads hibernate time (s) resume time (s)
> --------------------------------------------------
> 3 12.14 18.86
> 4 12.28 17.48
> 5 11.09 16.77
> 6 11.08 16.44
>
> With 5–6 threads, resume latency improves by approximately 12% compared
> to the default 3-thread configuration, with negligible impact on
> hibernate time.
>
> Introduce a new kernel parameter `cmp_threads=` that allows users and
> integrators to tune the number of compression/decompression threads at
> boot. This provides a way to balance performance and CPU utilization
> across a wide range of hardware without recompiling the kernel.
>
> Signed-off-by: Xueqin Luo <luoxueqin@kylinos.cn>
> ---
> kernel/power/swap.c | 24 ++++++++++++++++++++----
> 1 file changed, 20 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
> index f8c13f5672ec..540cf902498c 100644
> --- a/kernel/power/swap.c
> +++ b/kernel/power/swap.c
> @@ -519,8 +519,8 @@ static int swap_writer_finish(struct swap_map_handle *handle,
> CMP_HEADER, PAGE_SIZE)
> #define CMP_SIZE (CMP_PAGES * PAGE_SIZE)
>
> -/* Maximum number of threads for compression/decompression. */
> -#define CMP_THREADS 3
> +/* Default number of threads for compression/decompression. */
> +static int cmp_threads = 3;
>
> /* Minimum/maximum number of pages for read buffering. */
> #define CMP_MIN_RD_PAGES 1024
> @@ -741,7 +741,7 @@ static int save_compressed_image(struct swap_map_handle *handle,
> * footprint.
> */
> nr_threads = num_online_cpus() - 1;
> - nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
> + nr_threads = clamp_val(nr_threads, 1, cmp_threads);
>
> page = (void *)__get_free_page(GFP_NOIO | __GFP_HIGH);
> if (!page) {
> @@ -1257,7 +1257,7 @@ static int load_compressed_image(struct swap_map_handle *handle,
> * footprint.
> */
> nr_threads = num_online_cpus() - 1;
> - nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
> + nr_threads = clamp_val(nr_threads, 1, cmp_threads);
>
> page = vmalloc_array(CMP_MAX_RD_PAGES, sizeof(*page));
> if (!page) {
> @@ -1697,3 +1697,19 @@ static int __init swsusp_header_init(void)
> }
>
> core_initcall(swsusp_header_init);
> +
> +static int __init cmp_threads_setup(char *str)
> +{
> + int rc = kstrtouint(str, 0, &cmp_threads);
> +
> + if (rc)
> + return rc;
> +
> + if (cmp_threads < 1)
> + cmp_threads = 3;
> +
> + return 1;
> +
> +}
> +
> +__setup("cmp_threads=", cmp_threads_setup);
So this is just a kernel command line option (and one with a cryptic
name for that matter).
To a minimum, it requires documentation in
Documentation/admin-guide/kernel-parameters.txt, but it also might be
run-time configurable, like pm_debug_messages for one example.
Also the name could be more self-explanatory, like
hibernate_compression_threads or similar.
Thanks!
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-10-20 19:14 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-14 7:14 [PATCH v4 0/2] PM: hibernate: make compression threads configurable and support dynamic crc arrays Xueqin Luo
2025-10-14 7:14 ` [PATCH v4 1/2] PM: hibernate: dynamically allocate crc->unc_len/unc for configurable threads Xueqin Luo
2025-10-14 7:14 ` [PATCH v4 2/2] PM: hibernate: make compression threads configurable Xueqin Luo
2025-10-20 19:14 ` Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).