* [RFC PATCH] mm/page_reporting: Add page_reporting_delay sysctl
@ 2026-07-14 17:14 pratmal
2026-07-15 12:59 ` David Hildenbrand (Arm)
0 siblings, 1 reply; 3+ messages in thread
From: pratmal @ 2026-07-14 17:14 UTC (permalink / raw)
To: Andrew Morton, Vlastimil Babka
Cc: David Hildenbrand, Greg Thelen, Pratyush Mallick,
Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
Johannes Weiner, Zi Yan, linux-mm, linux-kernel
From: Pratyush Mallick <pratmal@google.com>
Currently, the free page reporting daemon uses a hardcoded delay of
(2 HZ) between reporting intervals. While this is a reasonable
default, it lacks the flexibility to adapt to varying guest workloads.
A low delay allows aggressive memory reclamation, returning unused
pages to the hypervisor as quickly as possible. However, during spiky
allocation/free churn, this immediate reporting can lead to a severe
performance penalty (nested page faults) as the guest re-allocates memory
that the hypervisor has just unmapped. In these scenarios, there is benefit
from increasing the delay to batch free pages over a longer window,
absorbing the churn without hypercall and re-fault overhead.
This patch refactors the delay into a dynamically tunable sysctl,
/proc/sys/vm/page_reporting_delay, measured in milliseconds. The value
defaults to 2000ms to precisely match the original (2 HZ) behavior.
If the sysctl is modified across reporting windows, the sysctl handler
immediately issues a mod_delayed_work() to honor the new configuration
without waiting for the prior timeout to lapse.
Signed-off-by: Pratyush Mallick <pratmal@google.com>
---
Sending this as an RFC to get thoughts on exposing this delay as a sysctl.
Benchmark Results:
We kill a process allocated with 10GB memory within the VM and mesure the
time it takes to report all the memory to host as well the delay in
initiating the reporting.
default(2s delay): https://drive.google.com/file/d/1Ouxm_raj4xPNthc_ryk0Mdbo-c_zXKiP/view?usp=sharing
Tuned to 0s delay: https://drive.google.com/file/d/1mk58LPiYgIF4Yk6kmX5JHplhrwIw0NbC/view?usp=sharing
The data shows (sysctl.vm.page_reporting_delay=0) that within ~2 seconds,
the guest reports ~10 GiB and the reporting is initiated as soon as 100ms.
With the default 2s delay, it takes around ~7 sec to report the same and
initiation delay is around 2 sec.
mm/page_reporting.c | 47 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index f0042d5743af..6fde542cbe09 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -6,6 +6,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/sysctl.h>
#include <linux/scatterlist.h>
#include "page_reporting.h"
@@ -47,15 +48,44 @@ MODULE_PARM_DESC(page_reporting_order, "Set page reporting order");
*/
EXPORT_SYMBOL_GPL(page_reporting_order);
-#define PAGE_REPORTING_DELAY (2 * HZ)
-static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
-
enum {
PAGE_REPORTING_IDLE = 0,
PAGE_REPORTING_REQUESTED,
PAGE_REPORTING_ACTIVE
};
+static unsigned int page_reporting_delay = 2000;
+static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
+
+static int page_reporting_delay_sysctl(const struct ctl_table *table, int write,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int ret;
+ struct page_reporting_dev_info *prdev;
+
+ ret = proc_dointvec(table, write, buffer, lenp, ppos);
+ if (ret < 0 || !write)
+ return ret;
+
+ rcu_read_lock();
+ prdev = rcu_dereference(pr_dev_info);
+ if (prdev && atomic_read(&prdev->state) == PAGE_REPORTING_REQUESTED)
+ mod_delayed_work(system_wq, &prdev->work, msecs_to_jiffies(page_reporting_delay));
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static struct ctl_table page_reporting_sysctls[] = {
+ {
+ .procname = "page_reporting_delay",
+ .data = &page_reporting_delay,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = page_reporting_delay_sysctl,
+ },
+};
+
/* request page reporting */
static void
__page_reporting_request(struct page_reporting_dev_info *prdev)
@@ -80,7 +110,7 @@ __page_reporting_request(struct page_reporting_dev_info *prdev)
* now we are limiting this to running no more than once every
* couple of seconds.
*/
- schedule_delayed_work(&prdev->work, PAGE_REPORTING_DELAY);
+ schedule_delayed_work(&prdev->work, msecs_to_jiffies(page_reporting_delay));
}
/* notify prdev of free page reporting request */
@@ -343,7 +373,7 @@ static void page_reporting_process(struct work_struct *work)
*/
state = atomic_cmpxchg(&prdev->state, state, PAGE_REPORTING_IDLE);
if (state == PAGE_REPORTING_REQUESTED)
- schedule_delayed_work(&prdev->work, PAGE_REPORTING_DELAY);
+ schedule_delayed_work(&prdev->work, msecs_to_jiffies(page_reporting_delay));
}
static DEFINE_MUTEX(page_reporting_mutex);
@@ -415,3 +445,10 @@ void page_reporting_unregister(struct page_reporting_dev_info *prdev)
mutex_unlock(&page_reporting_mutex);
}
EXPORT_SYMBOL_GPL(page_reporting_unregister);
+
+static int __init page_reporting_sysctl_init(void)
+{
+ register_sysctl_init("vm", page_reporting_sysctls);
+ return 0;
+}
+late_initcall(page_reporting_sysctl_init);
--
2.55.0.141.g00534a21ce-goog
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC PATCH] mm/page_reporting: Add page_reporting_delay sysctl
2026-07-14 17:14 [RFC PATCH] mm/page_reporting: Add page_reporting_delay sysctl pratmal
@ 2026-07-15 12:59 ` David Hildenbrand (Arm)
2026-07-16 3:30 ` Anshuman Khandual
0 siblings, 1 reply; 3+ messages in thread
From: David Hildenbrand (Arm) @ 2026-07-15 12:59 UTC (permalink / raw)
To: pratmal, Andrew Morton, Vlastimil Babka
Cc: Greg Thelen, Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
Johannes Weiner, Zi Yan, linux-mm, linux-kernel
On 7/14/26 19:14, pratmal@google.com wrote:
> From: Pratyush Mallick <pratmal@google.com>
>
> Currently, the free page reporting daemon uses a hardcoded delay of
> (2 HZ) between reporting intervals. While this is a reasonable
> default, it lacks the flexibility to adapt to varying guest workloads.
>
> A low delay allows aggressive memory reclamation, returning unused
> pages to the hypervisor as quickly as possible. However, during spiky
> allocation/free churn, this immediate reporting can lead to a severe
> performance penalty (nested page faults) as the guest re-allocates memory
> that the hypervisor has just unmapped. In these scenarios, there is benefit
> from increasing the delay to batch free pages over a longer window,
> absorbing the churn without hypercall and re-fault overhead.
>
> This patch refactors the delay into a dynamically tunable sysctl,
> /proc/sys/vm/page_reporting_delay, measured in milliseconds. The value
> defaults to 2000ms to precisely match the original (2 HZ) behavior.
> If the sysctl is modified across reporting windows, the sysctl handler
> immediately issues a mod_delayed_work() to honor the new configuration
> without waiting for the prior timeout to lapse.
>
> Signed-off-by: Pratyush Mallick <pratmal@google.com>
> ---
>
> Sending this as an RFC to get thoughts on exposing this delay as a sysctl.
>
> Benchmark Results:
> We kill a process allocated with 10GB memory within the VM and mesure the
> time it takes to report all the memory to host as well the delay in
> initiating the reporting.
>
> default(2s delay): https://drive.google.com/file/d/1Ouxm_raj4xPNthc_ryk0Mdbo-c_zXKiP/view?usp=sharing
> Tuned to 0s delay: https://drive.google.com/file/d/1mk58LPiYgIF4Yk6kmX5JHplhrwIw0NbC/view?usp=sharing
[...]
Hi!
>
> #include "page_reporting.h"
> @@ -47,15 +48,44 @@ MODULE_PARM_DESC(page_reporting_order, "Set page reporting order");
> */
> EXPORT_SYMBOL_GPL(page_reporting_order);
>
> -#define PAGE_REPORTING_DELAY (2 * HZ)
> -static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
> -
Why are you moving that?
> enum {
> PAGE_REPORTING_IDLE = 0,
> PAGE_REPORTING_REQUESTED,
> PAGE_REPORTING_ACTIVE
> };
>
> +static unsigned int page_reporting_delay = 2000;
Maybe "2 * MSEC_PER_SEC;"
Would we want to call that page_reporting_delay_ms to make it clearer what we
are dealing with?
> +static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
> +
> +static int page_reporting_delay_sysctl(const struct ctl_table *table, int write,
> + void *buffer, size_t *lenp, loff_t *ppos)
We prefer two tabs here in MM land.
> +{
> + int ret;
> + struct page_reporting_dev_info *prdev;
> +
> + ret = proc_dointvec(table, write, buffer, lenp, ppos);
> + if (ret < 0 || !write)
> + return ret;
Would we want to cap it at reasonable values?
> +
> + rcu_read_lock();
> + prdev = rcu_dereference(pr_dev_info);
> + if (prdev && atomic_read(&prdev->state) == PAGE_REPORTING_REQUESTED)
> + mod_delayed_work(system_wq, &prdev->work, msecs_to_jiffies(page_reporting_delay));
> + rcu_read_unlock();
Is that really required? Seems unnecessary given that we expect something in the
range of a couple of seconds max.
--
Cheers,
David
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC PATCH] mm/page_reporting: Add page_reporting_delay sysctl
2026-07-15 12:59 ` David Hildenbrand (Arm)
@ 2026-07-16 3:30 ` Anshuman Khandual
0 siblings, 0 replies; 3+ messages in thread
From: Anshuman Khandual @ 2026-07-16 3:30 UTC (permalink / raw)
To: David Hildenbrand (Arm), pratmal, Andrew Morton, Vlastimil Babka
Cc: Greg Thelen, Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
Johannes Weiner, Zi Yan, linux-mm, linux-kernel
On 15/07/26 6:29 PM, David Hildenbrand (Arm) wrote:
> On 7/14/26 19:14, pratmal@google.com wrote:
>> From: Pratyush Mallick <pratmal@google.com>
>>
>> Currently, the free page reporting daemon uses a hardcoded delay of
>> (2 HZ) between reporting intervals. While this is a reasonable
>> default, it lacks the flexibility to adapt to varying guest workloads.
>>
>> A low delay allows aggressive memory reclamation, returning unused
>> pages to the hypervisor as quickly as possible. However, during spiky
>> allocation/free churn, this immediate reporting can lead to a severe
>> performance penalty (nested page faults) as the guest re-allocates memory
>> that the hypervisor has just unmapped. In these scenarios, there is benefit
>> from increasing the delay to batch free pages over a longer window,
>> absorbing the churn without hypercall and re-fault overhead.
>>
>> This patch refactors the delay into a dynamically tunable sysctl,
>> /proc/sys/vm/page_reporting_delay, measured in milliseconds. The value
>> defaults to 2000ms to precisely match the original (2 HZ) behavior.
>> If the sysctl is modified across reporting windows, the sysctl handler
>> immediately issues a mod_delayed_work() to honor the new configuration
>> without waiting for the prior timeout to lapse.
>>
>> Signed-off-by: Pratyush Mallick <pratmal@google.com>
>> ---
>>
>> Sending this as an RFC to get thoughts on exposing this delay as a sysctl.
>>
>> Benchmark Results:
>> We kill a process allocated with 10GB memory within the VM and mesure the
>> time it takes to report all the memory to host as well the delay in
>> initiating the reporting.
>>
>> default(2s delay): https://drive.google.com/file/d/1Ouxm_raj4xPNthc_ryk0Mdbo-c_zXKiP/view?usp=sharing
>> Tuned to 0s delay: https://drive.google.com/file/d/1mk58LPiYgIF4Yk6kmX5JHplhrwIw0NbC/view?usp=sharing
>
> [...]
>
> Hi!
>
>>
>> #include "page_reporting.h"
>> @@ -47,15 +48,44 @@ MODULE_PARM_DESC(page_reporting_order, "Set page reporting order");
>> */
>> EXPORT_SYMBOL_GPL(page_reporting_order);
>>
>> -#define PAGE_REPORTING_DELAY (2 * HZ)
>> -static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
>> -
>
> Why are you moving that?
+1
>
>> enum {
>> PAGE_REPORTING_IDLE = 0,
>> PAGE_REPORTING_REQUESTED,
>> PAGE_REPORTING_ACTIVE
>> };
>>
>> +static unsigned int page_reporting_delay = 2000;
>
> Maybe "2 * MSEC_PER_SEC;"
> > Would we want to call that page_reporting_delay_ms to make it clearer what we
> are dealing with?
+1
>
>> +static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;
>> +
>> +static int page_reporting_delay_sysctl(const struct ctl_table *table, int write,
>> + void *buffer, size_t *lenp, loff_t *ppos)
>
> We prefer two tabs here in MM land.
>
>> +{
>> + int ret;
>> + struct page_reporting_dev_info *prdev;
>> +
>> + ret = proc_dointvec(table, write, buffer, lenp, ppos);
>> + if (ret < 0 || !write)
>> + return ret;
>
> Would we want to cap it at reasonable values?
Possibly with a macro PAGE_REPORTING_DELAY_MS_MAX or similar.
>
>> +
>> + rcu_read_lock();
>> + prdev = rcu_dereference(pr_dev_info);
>> + if (prdev && atomic_read(&prdev->state) == PAGE_REPORTING_REQUESTED)
>> + mod_delayed_work(system_wq, &prdev->work, msecs_to_jiffies(page_reporting_delay));
>> + rcu_read_unlock();
>
> Is that really required? Seems unnecessary given that we expect something in the
> range of a couple of seconds max.
Agreed.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-16 3:30 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-14 17:14 [RFC PATCH] mm/page_reporting: Add page_reporting_delay sysctl pratmal
2026-07-15 12:59 ` David Hildenbrand (Arm)
2026-07-16 3:30 ` Anshuman Khandual
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox