mm/damon: provide pseudo moving sum probe_hits
Subsystems (2)
SJ Park
maintainercover mm/damon: provide pseudo moving sum probe_hits
Data attribute counters (probe_hits) of DAMON are managed in the classical way. The counter value is accumulated every sampling interval, gets the complete view at the end of the aggregation interval, and is reset when the next aggregation interval starts. Hence, the complete view can be retrieved only once per aggregation interval, which can be quite long. With the suggested intervals autotuning setup, it becomes 2-4 seconds in common real production systems. It can span up to 200 seconds in theory. This will restrict online monitoring use case of DAMON.
Actually DAMON is already providing online monitoring of probe_hits. DAMON sysfs interface exposes the values via schemes tried regions directory files. However, due to the above mentioned limitation, it usually shows only partially accumulated hit counters and therefore not useful.
DAMOS is not using probe_hits at the moment. In the future, using it can further strengthen DAMOS. However, a recommended setup of DAMOS is utilizing sampling/aggregation intervals auto-tuning, and having its own DAMOS apply_interval (1 second is mostly recommended). In the setup, DAMOS will nearly always show incompletely accumulated probe_hits, which will not really be useful.
Data frequency counter (nr_accesses) of DAMON solves this problem using the pseudo moving sum value. The infrastructure is not limited to nr_accesses but general sampling based counters. Maintain and provide the pseudo moving sum of probe_hits similar to nr_accesses, using the infrastructure.
Tests
=====
On an idle system, I ran DAMON with an attribute probe filter for non-anonymous page, using DAMON user-space tool, damo [1], like below.
$ sudo ./damo start --probe_filter allow non anon
Because the system is idle, nearly all memory is not an anonymous page but a free page, so the probe_hits are expected to be nearly always full. In this setup, since the sampling interval is 5ms and the aggregation interval is 100ms, the counter value is expected to always be near 20.
On kernels not having this series, if we retrieve the probe hits in an arbitrary time that is likely not aligned to the aggregation interval, the values are usually much lower than the expectation like below. This is because the tool is showing the incompletely aggregated values.
$ sudo ./damo report access --format append region "probe_hits: <probe hits>"
heatmap: 00000000000000000000000000000000000000008999999711111111000000000000000000000000
# min/max temperatures: -1,630,000,000, 0, column size: 99.800 MiB
intervals: sample 5 ms aggr 100 ms (max access hz 200)
0 addr 4.000 KiB size 3.898 GiB access 0 hz age 16.300 s probe_hits: 11
1 addr 3.898 GiB size 77.859 MiB access 0 hz age 1.500 s probe_hits: 11
2 addr 3.974 GiB size 700.770 MiB access 0 hz age 0 ns probe_hits: 11
3 addr 4.659 GiB size 791.078 MiB access 0 hz age 13.700 s probe_hits: 11
4 addr 5.431 GiB size 1.472 GiB access 0 hz age 15.800 s probe_hits: 11
5 addr 6.903 GiB size 915.059 MiB access 0 hz age 15.300 s probe_hits: 11
memory bw estimate: 0 B per second
total size: 7.797 GiB
record DAMON intervals: sample 5 ms, aggr 100 msAfter applying this series, I was able to reliably show the expected results like below.
$ sudo ./damo report access --format append region "probe_hits: <probe hits>"
heatmap: 00000000333333330000000166666665111111139999999855555555333333333333333444444444
intervals: sample 5 ms aggr 100 ms (max access hz 200)
0 addr 4.000 KiB size 790.496 MiB access 0 hz age 1 m 33.300 s probe_hits: 20
1 addr 790.500 MiB size 791.160 MiB access 0 hz age 1 m 15.400 s probe_hits: 19
2 addr 1.545 GiB size 792.316 MiB access 0 hz age 1 m 32.400 s probe_hits: 19
3 addr 2.318 GiB size 795.465 MiB access 0 hz age 1 m 2.600 s probe_hits: 19
4 addr 3.095 GiB size 797.102 MiB access 0 hz age 1 m 23.500 s probe_hits: 20
5 addr 3.874 GiB size 797.293 MiB access 0 hz age 47.900 s probe_hits: 20
6 addr 4.652 GiB size 787.516 MiB access 0 hz age 1 m 3.800 s probe_hits: 20
7 addr 5.421 GiB size 784.461 MiB access 0 hz age 1 m 14.400 s probe_hits: 19
8 addr 6.187 GiB size 795.621 MiB access 0 hz age 1 m 15.700 s probe_hits: 20
9 addr 6.964 GiB size 798.000 MiB access 0 hz age 1 m 10.200 s probe_hits: 20
10 addr 7.744 GiB size 54.566 MiB access 0 hz age 1 m 9.300 s probe_hits: 20
memory bw estimate: 0 B per second
total size: 7.797 GiB
record DAMON intervals: sample 5 ms, aggr 100 msFYI, 'damo report access' output format has changed on v3.3.0. Above outputs can be reproduced on <3.3.0 versions of damo.
Patches Sequence
================
Patch 1 adds probe_hits counters for values that fully accumulated in the last aggregation interval. This is required for using the moving sum infrastructure. Patch 2 introduces a function for getting the
moving sum values on demand, using the infrastructure. Finally, patch
3 updates the DAMON sysfs interface to expose the moving sum values to the schemes tried regions directory.
Changelog
=========
Chnges from RFC v1
- RFC v1: https://lore.kernel.org/[email protected]
- Rebase to the latest mm-new.
[1] https://github.com/damonitor/damo
SJ Park (3):
mm/damon: add damon_region->last_probe_hits mm/damon/core: introduce damon_probe_hits_mvsum() mm/damon/sysfs-schemes: set probe hits as pseudo moving sums
include/linux/damon.h | 4 +++- mm/damon/core.c | 31 +++++++++++++++++++++++++++++-- mm/damon/sysfs-schemes.c | 3 ++- 3 files changed, 34 insertions(+), 4 deletions(-)
base-commit: 863594ffd4066f35cc62893902c843b0c2a87c65
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 1/3 mm/damon: add damon_region->last_probe_hits
Add new damon_region filed, last_probe_hits. Maintain fully accumulated probe_hits values from the last aggregation interval in the field.
--- include/linux/damon.h | 2 +- mm/damon/core.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-)
include/linux/damon.h +1 -1
@@ -68,10 +68,10 @@ struct damon_region {unsigned int nr_accesses;unsigned char probe_hits[DAMON_MAX_PROBES ];struct list_head list; -unsigned int age;/* private: Internal value for age calculation. */ unsigned int last_nr_accesses; +unsigned char last_probe_hits[DAMON_MAX_PROBES ]; };/**
mm/damon/core.c +8 -2
@@ -302,8 +302,10 @@ struct damon_region *damon_new_region(unsigned long start, unsigned long end) region->ar.start = start; region->ar.end = end; region->nr_accesses =0 ; -for (i =0 ; i <DAMON_MAX_PROBES ; i++) +for (i =0 ; i <DAMON_MAX_PROBES ; i++) { region->probe_hits[i] =0 ; + region->last_probe_hits[i] =0 ; + }INIT_LIST_HEAD (®ion->list); region->age =0 ;
@@ -2047,8 +2049,10 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) damon_nr_regions(t), nr_probes); r->last_nr_accesses = r->nr_accesses; r->nr_accesses =0 ; -for (i =0 ; i <DAMON_MAX_PROBES ; i++) +for (i =0 ; i <DAMON_MAX_PROBES ; i++) { + r->last_probe_hits[i] = r->probe_hits[i]; r->probe_hits[i] =0 ; + } } ti++; }
@@ -3239,6 +3243,8 @@ static void damon_split_region_at(struct damon_target *t, new->nr_accesses = r->nr_accesses;/* todo: do this for only installed probes */ memcpy (new->probe_hits, r->probe_hits,sizeof (r->probe_hits)); +memcpy (new->last_probe_hits, r->last_probe_hits, +sizeof (r->last_probe_hits));damon_insert_region (new, r,damon_next_region (r), t); }
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH v1.1 1/3] mm/damon: add damon_region->last_probe_hits
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] When `damon_update_monitoring_result()` is called to apply new attributes mid-aggregation, it…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] When damon_update_monitoring_result() is called to apply new attributes mid-aggregation, it resets r->nr_accesses but fails to clear r->probe_hits. As a result, accumulated probe hits leak across the aborted interval boundary. Furthermore, the newly introduced r->last_probe_hits field is completely ignored by this function—it is neither scaled for the new interval attributes (unlike last_nr_accesses) nor protected from the probe_hits leak. This causes the newly introduced moving sum statistics exposed to userspace to become artificially inflated and mathematically incorrect after an attribute update. --
commit c9f161ddb2f122eeb9bddfba63cb77e65fe86f9c
Author: SJ Park <[email protected]>
mm/damon: add damon_region->last_probe_hits
Add new damon_region field, last_probe_hits. Maintain fully accumulated probe_hits values from the last aggregation interval in the field.
Quoted 16 lines
include/linux/damon.h +1
-1@@ -68,10 +68,10 @@ struct damon_region {unsigned int nr_accesses;unsigned char probe_hits[DAMON_MAX_PROBES ];struct list_head list; -unsigned int age;/* private: Internal value for age calculation. */ unsigned int last_nr_accesses; +unsigned char last_probe_hits[DAMON_MAX_PROBES ]; };/**
[ ... ]
Quoted 4 lines
mm/damon/core.c +0
-0
[ ... ]
mm/damon/core.c static void kdamond_reset_aggregated(struct damon_ctx *c) · line 2048
Quoted 9 lines
mm/damon/core.c +3
-1@@ -2040,8 +2042,10 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) damon_nr_regions(t), nr_probes); r->last_nr_accesses = r->nr_accesses; r->nr_accesses =0 ; -for (i =0 ; i <DAMON_MAX_PROBES ; i++) +for (i =0 ; i <DAMON_MAX_PROBES ; i++) { + r->last_probe_hits[i] = r->probe_hits[i]; r->probe_hits[i] =0 ; + }
[Severity: Medium]
Is there a regression in how statistics are updated when attributes change mid-aggregation?
If damon_update_monitoring_result() is called to apply new attributes, it resets nr_accesses but doesn't clear the probe_hits array:
mm/damon/core.c:damon_update_monitoring_result() {
...
if (!aggregating)
r->nr_accesses = damon_nr_accesses_for_new_attrs(
r->nr_accesses, old_attrs, new_attrs);
else
/*
* if this is called in the middle of the aggregation, reset
* the aggregations we made so far for this aggregation
* interval. In other words, make the status like
* kdamond_reset_aggregated() is called.
*/
r->nr_accesses = 0;
...
}This appears to completely ignore the newly introduced last_probe_hits array.
Since last_nr_accesses is scaled for the new interval attributes, should last_probe_hits also be scaled to maintain accurate moving sum statistics?
Also, should probe_hits be cleared for mid-aggregation updates to prevent leaking accumulated counts into the aborted interval?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
SJ Park
maintainerRe: [RFC PATCH v1.1 1/3] mm/damon: add damon_region->last_probe_hits
Quoted 71 lines · On Thu, 02 Jul 2026 17:29:05 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Whendamon_update_monitoring_result()is called to apply new attributes mid-aggregation, it resetsr->nr_accessesbut fails to clearr->probe_hits. As a result, accumulated probe hits leak across the aborted interval boundary. Furthermore, the newly introducedr->last_probe_hitsfield is completely ignored by this function—it is neither scaled for the new interval attributes (unlikelast_nr_accesses) nor protected from theprobe_hitsleak. This causes the newly introduced moving sum statistics exposed to userspace to become artificially inflated and mathematically incorrect after an attribute update. --commit
c9f161ddb2f122eeb9bddfba63cb77e65fe86f9c
Author: SJ Park <[email protected]>mm/damon: add
damon_region->last_probe_hitsAdd new
damon_regionfield,last_probe_hits. Maintain fully accumulatedprobe_hitsvalues from the last aggregation interval in the field.Quoted 16 lines
include/linux/damon.h +1
-1@@ -68,10 +68,10 @@ struct damon_region {unsigned int nr_accesses;unsigned char probe_hits[DAMON_MAX_PROBES ];struct list_head list; -unsigned int age;/* private: Internal value for age calculation. */ unsigned int last_nr_accesses; +unsigned char last_probe_hits[DAMON_MAX_PROBES ]; };/** [ ... ]
Quoted 4 lines
mm/damon/core.c +0
-0[ ... ]
mm/damon/core.c static void kdamond_reset_aggregated(struct damon_ctx *c) · line 2048
Quoted 9 lines
mm/damon/core.c +3
-1@@ -2040,8 +2042,10 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) damon_nr_regions(t), nr_probes); r->last_nr_accesses = r->nr_accesses; r->nr_accesses =0 ; -for (i =0 ; i <DAMON_MAX_PROBES ; i++) +for (i =0 ; i <DAMON_MAX_PROBES ; i++) { + r->last_probe_hits[i] = r->probe_hits[i]; r->probe_hits[i] =0 ; + }[Severity: Medium]
Is there a regression in how statistics are updated when attributes change mid-aggregation?If
damon_update_monitoring_result()is called to apply new attributes, it resetsnr_accessesbut doesn't clear theprobe_hitsarray:mm/damon/core.c:damon_update_monitoring_result() { ... if (!aggregating) r->nr_accesses = damon_nr_accesses_for_new_attrs( r->nr_accesses, old_attrs, new_attrs); else /* * if this is called in the middle of the aggregation, reset * the aggregations we made so far for this aggregation * interval. In other words, make the status like * kdamond_reset_aggregated() is called. */ r->nr_accesses = 0; ... }
Quoted 7 lines
This appears to completely ignore the newly introduced
last_probe_hitsarray.Since
last_nr_accessesis scaled for the new interval attributes, shouldlast_probe_hitsalso be scaled to maintain accurate moving sum statistics?Also, should
probe_hitsbe cleared for mid-aggregation updates to prevent leaking accumulated counts into the aborted interval?
This is indeed something that can better improved.
The function is not updating probe_hits, either, though. So no regression. Not a blocker of this patch.
Thanks,
SJ
[...]
SJ Park
maintainerRFC PATCH 2/3 mm/damon/core: introduce damon_probe_hits_mvsum()
In reply to SJ ParkImplement a function for getting a reasonable best effort quality pseudo moving sums of probe_hits on demands. It reuses the internal function for the pseudo moving sum for data access frequency (nr_accesses).
--- include/linux/damon.h | 2 ++ mm/damon/core.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+)
include/linux/damon.h +2 -0
@@ -1003,6 +1003,8 @@ void damon_add_probe(struct damon_ctx *ctx, struct damon_probe *probe);struct damon_region *damon_new_region (unsigned long start,unsigned long end);unsigned int damon_nr_accesses_mvsum (struct damon_region *r,struct damon_ctx *ctx); +unsigned char damon_probe_hits_mvsum (int probe_idx,struct damon_region *r, +struct damon_ctx *ctx);int damon_set_regions (struct damon_target *t,struct damon_addr_range *ranges,unsigned int nr_ranges,unsigned long min_region_sz);
mm/damon/core.c +21 -0
@@ -273,6 +273,27 @@ unsigned int damon_nr_accesses_mvsum(struct damon_region *r, left_window_bp); } +unsigned char damon_probe_hits_mvsum (int probe_idx,struct damon_region *r, +struct damon_ctx *ctx) +{ +unsigned long sample_interval, aggr_interval; +unsigned long window_len, left_window, left_window_bp; + + sample_interval = ctx->attrs.sample_interval ? :1 ; + aggr_interval = ctx->attrs.aggr_interval ? :1 ; + window_len = aggr_interval / sample_interval; +if (time_after_eq (ctx->passed_sample_intervals, + ctx->next_aggregation_sis)) + left_window =0 ; +else + left_window = ctx->next_aggregation_sis - + ctx->passed_sample_intervals; + left_window_bp =mult_frac (left_window,10000 , window_len); + +return damon_mvsum (r->probe_hits[probe_idx], + r->last_probe_hits[probe_idx], left_window_bp); +} +#ifdef CONFIG_DAMON_DEBUG_SANITY static void damon_verify_new_region (unsigned long start,unsigned long end) {
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 3/3 mm/damon/sysfs-schemes: set probe hits as pseudo moving sums
In reply to SJ ParkDAMON sysfs interface exposes damon_region->probe_hits via probe hit files. Because the counters are completed only at the end of the aggregation interval, users can show incomplete values if they requested the file content update (update_schemes_tried_regions command) in the middle of an aggregation interval. Set the value as the pseudo moving sum value of the counter, similar to that for nr_accesses.
--- mm/damon/sysfs-schemes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
mm/damon/sysfs-schemes.c +2 -1
@@ -110,7 +110,8 @@ static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes,struct damos_sysfs_probe *sys_probe;int err; - sys_probe =damos_sysfs_probe_alloc (region->probe_hits[i]); + sys_probe =damos_sysfs_probe_alloc ( +damon_probe_hits_mvsum (i, region, ctx));if (!sys_probe) {damos_sysfs_probes_rm_dirs (probes);return -ENOMEM ;
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH v1.1 3/3] mm/damon/sysfs-schemes: set probe hits as pseudo moving sums
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] damon_probe_hits_mvsum() returns an artificially inflated moving sum when left_window_bp ==…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] damon_probe_hits_mvsum() returns an artificially inflated moving sum when left_window_bp == 10000 after an attribute update. --
commit aa52db4de056d7c850beaa9ef06ec63a3befcbf2
Author: SJ Park <[email protected]>
mm/damon/sysfs-schemes: set probe hits as pseudo moving sums
This commit updates the DAMON sysfs interface to expose probe hits using a pseudo moving sum instead of incomplete counters. It uses damon_probe_hits_mvsum() to calculate the value, similar to the logic used for nr_accesses.
mm/damon/sysfs-schemes.c static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes, · line 114
Quoted 11 lines
mm/damon/sysfs-schemes.c +2
-1@@ -110,7 +110,8 @@ static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes,struct damos_sysfs_probe *sys_probe;int err; - sys_probe =damos_sysfs_probe_alloc (region->probe_hits[i]); + sys_probe =damos_sysfs_probe_alloc ( +damon_probe_hits_mvsum (i, region, ctx));
[Severity: Medium]
Can this result in an artificially inflated moving sum being exposed to userspace?
Looking at damon_probe_hits_mvsum() in mm/damon/core.c:
mm/damon/core.c:damon_probe_hits_mvsum() {
...
return damon_mvsum(r->probe_hits[probe_idx],
r->last_probe_hits[probe_idx], left_window_bp);
}When left_window_bp == 10000 after an attribute update, this calculates current + last.
Because r->probe_hits is not cleared during attribute updates, the un-cleared partial hits might be erroneously added to the previous interval's hits. This function seems to lack the safeguard for this condition that is present in damon_nr_accesses_mvsum().
If users query the stats immediately after an update, could this silently overflow the unsigned char and expose incorrect statistics?
Quoted 3 lines
mm/damon/sysfs-schemes.c +0
-0if (!sys_probe) {damos_sysfs_probes_rm_dirs (probes);return -ENOMEM ;
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
SJ Park
maintainerRe: [RFC PATCH v1.1 3/3] mm/damon/sysfs-schemes: set probe hits as pseudo moving sums
Quoted 41 lines · On Thu, 02 Jul 2026 17:32:07 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium]damon_probe_hits_mvsum()returns an artificially inflated moving sum whenleft_window_bp== 10000 after an attribute update. --commit
aa52db4de056d7c850beaa9ef06ec63a3befcbf2
Author: SJ Park <[email protected]>
mm/damon/sysfs-schemes: set probe hits as pseudo moving sumsThis commit updates the DAMON sysfs interface to expose probe hits using a pseudo moving sum instead of incomplete counters. It uses
damon_probe_hits_mvsum()to calculate the value, similar to the logic used fornr_accesses.mm/damon/sysfs-schemes.c static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes, · line 114
Quoted 11 lines
mm/damon/sysfs-schemes.c +2
-1@@ -110,7 +110,8 @@ static int damos_sysfs_probes_add_dirs(struct damos_sysfs_probes *probes,struct damos_sysfs_probe *sys_probe;int err; - sys_probe =damos_sysfs_probe_alloc (region->probe_hits[i]); + sys_probe =damos_sysfs_probe_alloc ( +damon_probe_hits_mvsum (i, region, ctx));[Severity: Medium]
Can this result in an artificially inflated moving sum being exposed to userspace?Looking at
damon_probe_hits_mvsum()inmm/damon/core.c:mm/damon/core.c:damon_probe_hits_mvsum() { ... return damon_mvsum(r->probe_hits[probe_idx], r->last_probe_hits[probe_idx], left_window_bp); }When
left_window_bp== 10000 after an attribute update, this calculates current + last.
Quoted 7 lines
Because
r->probe_hitsis not cleared during attribute updates, the un-cleared partial hits might be erroneously added to the previous interval's hits. This function seems to lack the safeguard for this condition that is present indamon_nr_accesses_mvsum().If users query the stats immediately after an update, could this silently overflow the unsigned char and expose incorrect statistics?
This is good thing to improve it for the perfect. But the perfect is the enemy of good ;)
probe_hits was very unreliable before this patch, and this patch makes it reliable but still having some rooms to improve.
Not a blocker for this patch, in my opinion.
Thanks,
SJ
[...]