When probe weights are configured (damon_has_probe_weights()), use damon_probe_hits_wsum() for the frequency subscore in damon_hot_score() instead of damon_nr_accesses_mvsum(). This routes hardware event counts from a perf-event probe into the tiering decision. When no probe weights are set the frequency subscore comes from nr_accesses_mvsum, so page-table-only monitoring scores from the page-table access rate. Export damon_has_probe_weights() so ops-common.c can call it without a static dependency on core.c internals. Guard against integer overflow: clamp the probe-weighted subscore to DAMON_MAX_SUBSCORE via min_t after the mult_frac scaling so a large weighted-hit sum cannot overflow the subscore range. Signed-off-by: Ravi Jonnalagadda --- include/linux/damon.h | 1 + mm/damon/core.c | 2 +- mm/damon/ops-common.c | 21 ++++++++++++++++++--- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index 88a459a60b296..3147ce30951f5 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -1307,6 +1307,7 @@ unsigned char damon_probe_hits_mvsum(int probe_idx, struct damon_region *r, struct damon_ctx *ctx); unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last, bool mv, struct damon_ctx *ctx); +bool damon_has_probe_weights(struct damon_ctx *c); int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges, unsigned int nr_ranges, unsigned long min_region_sz); diff --git a/mm/damon/core.c b/mm/damon/core.c index 850880f791c9e..6b3aa86386b76 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -391,7 +391,7 @@ static struct damon_probe *damon_nth_probe(int n, struct damon_ctx *ctx) return NULL; } -static bool damon_has_probe_weights(struct damon_ctx *c) +bool damon_has_probe_weights(struct damon_ctx *c) { struct damon_probe *p; diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c index c36cc39cd2c70..3033a5c0ba690 100644 --- a/mm/damon/ops-common.c +++ b/mm/damon/ops-common.c @@ -170,9 +170,24 @@ int damon_hot_score(struct damon_ctx *c, struct damon_region *r, unsigned int age_weight = s->quota.weight_age; int hotness; - freq_subscore = mult_frac(damon_nr_accesses_mvsum(r, c), - DAMON_MAX_SUBSCORE, - damon_nr_samples_per_aggr(&c->attrs)); + if (damon_has_probe_weights(c)) { + unsigned int wsum = damon_probe_hits_wsum(r, false, true, c); + + /* + * Route perf-event hardware event counts into the score. + * Clamp to DAMON_MAX_SUBSCORE so a large weighted-hit sum + * cannot overflow the subscore range. + */ + freq_subscore = min_t(int, + mult_frac(wsum, DAMON_MAX_SUBSCORE, + /* +1 guards divide-by-zero: samples-per-aggr can be 0 */ + damon_nr_samples_per_aggr(&c->attrs) + 1), + DAMON_MAX_SUBSCORE); + } else { + freq_subscore = mult_frac(damon_nr_accesses_mvsum(r, c), + DAMON_MAX_SUBSCORE, + damon_nr_samples_per_aggr(&c->attrs)); + } age_in_sec = (unsigned long)r->age * c->attrs.aggr_interval / 1000000; if (age_in_sec) -- 2.43.0