12224d848SSeongJae Park /* SPDX-License-Identifier: GPL-2.0 */
22224d848SSeongJae Park /*
32224d848SSeongJae Park * DAMON api
42224d848SSeongJae Park *
56ad59a38SSeongJae Park * Author: SeongJae Park <[email protected]>
62224d848SSeongJae Park */
72224d848SSeongJae Park
82224d848SSeongJae Park #ifndef _DAMON_H_
92224d848SSeongJae Park #define _DAMON_H_
102224d848SSeongJae Park
1198def236SSeongJae Park #include <linux/memcontrol.h>
122224d848SSeongJae Park #include <linux/mutex.h>
132224d848SSeongJae Park #include <linux/time64.h>
142224d848SSeongJae Park #include <linux/types.h>
159b2a38d6SXin Hao #include <linux/random.h>
162224d848SSeongJae Park
17b9a6ac4eSSeongJae Park /* Minimal region size. Every damon_region is aligned by this. */
18b9a6ac4eSSeongJae Park #define DAMON_MIN_REGION PAGE_SIZE
1938683e00SSeongJae Park /* Max priority score for DAMON-based operation schemes */
2038683e00SSeongJae Park #define DAMOS_MAX_SCORE (99)
21b9a6ac4eSSeongJae Park
229b2a38d6SXin Hao /* Get a random number in [l, r) */
damon_rand(unsigned long l,unsigned long r)23234d6873SXin Hao static inline unsigned long damon_rand(unsigned long l, unsigned long r)
24234d6873SXin Hao {
258032bf12SJason A. Donenfeld return l + get_random_u32_below(r - l);
26234d6873SXin Hao }
279b2a38d6SXin Hao
28f23b8eeeSSeongJae Park /**
29f23b8eeeSSeongJae Park * struct damon_addr_range - Represents an address region of [@start, @end).
30f23b8eeeSSeongJae Park * @start: Start address of the region (inclusive).
31f23b8eeeSSeongJae Park * @end: End address of the region (exclusive).
32f23b8eeeSSeongJae Park */
33f23b8eeeSSeongJae Park struct damon_addr_range {
34f23b8eeeSSeongJae Park unsigned long start;
35f23b8eeeSSeongJae Park unsigned long end;
36f23b8eeeSSeongJae Park };
37f23b8eeeSSeongJae Park
38f23b8eeeSSeongJae Park /**
390431c426SUsama Arif * struct damon_size_range - Represents size for filter to operate on [@min, @max].
400431c426SUsama Arif * @min: Min size (inclusive).
410431c426SUsama Arif * @max: Max size (inclusive).
420431c426SUsama Arif */
430431c426SUsama Arif struct damon_size_range {
440431c426SUsama Arif unsigned long min;
450431c426SUsama Arif unsigned long max;
460431c426SUsama Arif };
470431c426SUsama Arif
480431c426SUsama Arif /**
49f23b8eeeSSeongJae Park * struct damon_region - Represents a monitoring target region.
50f23b8eeeSSeongJae Park * @ar: The address range of the region.
51f23b8eeeSSeongJae Park * @sampling_addr: Address of the sample for the next access check.
52f23b8eeeSSeongJae Park * @nr_accesses: Access frequency of this region.
53ace30fb2SSeongJae Park * @nr_accesses_bp: @nr_accesses in basis point (0.01%) that updated for
54ace30fb2SSeongJae Park * each sampling interval.
55f23b8eeeSSeongJae Park * @list: List head for siblings.
56fda504faSSeongJae Park * @age: Age of this region.
57fda504faSSeongJae Park *
58d896073fSSeongJae Park * @nr_accesses is reset to zero for every &damon_attrs->aggr_interval and be
59d896073fSSeongJae Park * increased for every &damon_attrs->sample_interval if an access to the region
6078fbfb15SSeongJae Park * during the last sampling interval is found. The update of this field should
6178fbfb15SSeongJae Park * not be done with direct access but with the helper function,
6278fbfb15SSeongJae Park * damon_update_region_access_rate().
63d896073fSSeongJae Park *
6480333828SSeongJae Park * @nr_accesses_bp is another representation of @nr_accesses in basis point
65ace30fb2SSeongJae Park * (1 in 10,000) that updated for every &damon_attrs->sample_interval in a
66ace30fb2SSeongJae Park * manner similar to moving sum. By the algorithm, this value becomes
67ace30fb2SSeongJae Park * @nr_accesses * 10000 for every &struct damon_attrs->aggr_interval. This can
68ace30fb2SSeongJae Park * be used when the aggregation interval is too huge and therefore cannot wait
69ace30fb2SSeongJae Park * for it before getting the access monitoring results.
7080333828SSeongJae Park *
71fda504faSSeongJae Park * @age is initially zero, increased for each aggregation interval, and reset
72fda504faSSeongJae Park * to zero again if the access frequency is significantly changed. If two
73fda504faSSeongJae Park * regions are merged into a new region, both @nr_accesses and @age of the new
74fda504faSSeongJae Park * region are set as region size-weighted average of those of the two regions.
75f23b8eeeSSeongJae Park */
76f23b8eeeSSeongJae Park struct damon_region {
77f23b8eeeSSeongJae Park struct damon_addr_range ar;
78f23b8eeeSSeongJae Park unsigned long sampling_addr;
79f23b8eeeSSeongJae Park unsigned int nr_accesses;
8080333828SSeongJae Park unsigned int nr_accesses_bp;
81f23b8eeeSSeongJae Park struct list_head list;
82fda504faSSeongJae Park
83fda504faSSeongJae Park unsigned int age;
84fda504faSSeongJae Park /* private: Internal value for age calculation. */
85fda504faSSeongJae Park unsigned int last_nr_accesses;
86f23b8eeeSSeongJae Park };
87f23b8eeeSSeongJae Park
88f23b8eeeSSeongJae Park /**
89f23b8eeeSSeongJae Park * struct damon_target - Represents a monitoring target.
901971bd63SSeongJae Park * @pid: The PID of the virtual address space to monitor.
91b9a6ac4eSSeongJae Park * @nr_regions: Number of monitoring target regions of this target.
92f23b8eeeSSeongJae Park * @regions_list: Head of the monitoring target regions of this target.
93f23b8eeeSSeongJae Park * @list: List head for siblings.
94f23b8eeeSSeongJae Park *
95f23b8eeeSSeongJae Park * Each monitoring context could have multiple targets. For example, a context
96f23b8eeeSSeongJae Park * for virtual memory address spaces could have multiple target processes. The
97f7d911c3SSeongJae Park * @pid should be set for appropriate &struct damon_operations including the
98f7d911c3SSeongJae Park * virtual address spaces monitoring operations.
99f23b8eeeSSeongJae Park */
100f23b8eeeSSeongJae Park struct damon_target {
1011971bd63SSeongJae Park struct pid *pid;
102b9a6ac4eSSeongJae Park unsigned int nr_regions;
103f23b8eeeSSeongJae Park struct list_head regions_list;
104f23b8eeeSSeongJae Park struct list_head list;
105f23b8eeeSSeongJae Park };
106f23b8eeeSSeongJae Park
1071f366e42SSeongJae Park /**
1081f366e42SSeongJae Park * enum damos_action - Represents an action of a Data Access Monitoring-based
1091f366e42SSeongJae Park * Operation Scheme.
1101f366e42SSeongJae Park *
1111f366e42SSeongJae Park * @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED.
1121f366e42SSeongJae Park * @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD.
1131f366e42SSeongJae Park * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT.
1141f366e42SSeongJae Park * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE.
1151f366e42SSeongJae Park * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE.
1168cdcc532SSeongJae Park * @DAMOS_LRU_PRIO: Prioritize the region on its LRU lists.
11799cdc2cdSSeongJae Park * @DAMOS_LRU_DEPRIO: Deprioritize the region on its LRU lists.
118b696722dSHyeongtak Ji * @DAMOS_MIGRATE_HOT: Migrate the regions prioritizing warmer regions.
119b51820ebSHonggyu Kim * @DAMOS_MIGRATE_COLD: Migrate the regions prioritizing colder regions.
1202f0b548cSSeongJae Park * @DAMOS_STAT: Do nothing but count the stat.
1215257f36eSSeongJae Park * @NR_DAMOS_ACTIONS: Total number of DAMOS actions
122fb6f026bSSeongJae Park *
123fb6f026bSSeongJae Park * The support of each action is up to running &struct damon_operations.
124fb6f026bSSeongJae Park * &enum DAMON_OPS_VADDR and &enum DAMON_OPS_FVADDR supports all actions except
125fb6f026bSSeongJae Park * &enum DAMOS_LRU_PRIO and &enum DAMOS_LRU_DEPRIO. &enum DAMON_OPS_PADDR
126fb6f026bSSeongJae Park * supports only &enum DAMOS_PAGEOUT, &enum DAMOS_LRU_PRIO, &enum
127fb6f026bSSeongJae Park * DAMOS_LRU_DEPRIO, and &DAMOS_STAT.
1281f366e42SSeongJae Park */
1291f366e42SSeongJae Park enum damos_action {
1301f366e42SSeongJae Park DAMOS_WILLNEED,
1311f366e42SSeongJae Park DAMOS_COLD,
1321f366e42SSeongJae Park DAMOS_PAGEOUT,
1331f366e42SSeongJae Park DAMOS_HUGEPAGE,
1341f366e42SSeongJae Park DAMOS_NOHUGEPAGE,
1358cdcc532SSeongJae Park DAMOS_LRU_PRIO,
13699cdc2cdSSeongJae Park DAMOS_LRU_DEPRIO,
137b696722dSHyeongtak Ji DAMOS_MIGRATE_HOT,
138b51820ebSHonggyu Kim DAMOS_MIGRATE_COLD,
1392f0b548cSSeongJae Park DAMOS_STAT, /* Do nothing but only record the stat */
1405257f36eSSeongJae Park NR_DAMOS_ACTIONS,
1411f366e42SSeongJae Park };
1421f366e42SSeongJae Park
1431f366e42SSeongJae Park /**
144bcce9bc1SSeongJae Park * enum damos_quota_goal_metric - Represents the metric to be used as the goal
145bcce9bc1SSeongJae Park *
146bcce9bc1SSeongJae Park * @DAMOS_QUOTA_USER_INPUT: User-input value.
1472dbb60f7SSeongJae Park * @DAMOS_QUOTA_SOME_MEM_PSI_US: System level some memory PSI in us.
148bcce9bc1SSeongJae Park * @NR_DAMOS_QUOTA_GOAL_METRICS: Number of DAMOS quota goal metrics.
149bcce9bc1SSeongJae Park *
150bcce9bc1SSeongJae Park * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported.
151bcce9bc1SSeongJae Park */
152bcce9bc1SSeongJae Park enum damos_quota_goal_metric {
153bcce9bc1SSeongJae Park DAMOS_QUOTA_USER_INPUT,
1542dbb60f7SSeongJae Park DAMOS_QUOTA_SOME_MEM_PSI_US,
155bcce9bc1SSeongJae Park NR_DAMOS_QUOTA_GOAL_METRICS,
156bcce9bc1SSeongJae Park };
157bcce9bc1SSeongJae Park
158bcce9bc1SSeongJae Park /**
159106e26fcSSeongJae Park * struct damos_quota_goal - DAMOS scheme quota auto-tuning goal.
160bcce9bc1SSeongJae Park * @metric: Metric to be used for representing the goal.
161bcce9bc1SSeongJae Park * @target_value: Target value of @metric to achieve with the tuning.
162bcce9bc1SSeongJae Park * @current_value: Current value of @metric.
1632dbb60f7SSeongJae Park * @last_psi_total: Last measured total PSI
16491f21216SSeongJae Park * @list: List head for siblings.
165106e26fcSSeongJae Park *
16606ba5b30SSeongJae Park * Data structure for getting the current score of the quota tuning goal. The
16706ba5b30SSeongJae Park * score is calculated by how close @current_value and @target_value are. Then
16806ba5b30SSeongJae Park * the score is entered to DAMON's internal feedback loop mechanism to get the
16906ba5b30SSeongJae Park * auto-tuned quota.
170bcce9bc1SSeongJae Park *
171bcce9bc1SSeongJae Park * If @metric is DAMOS_QUOTA_USER_INPUT, @current_value should be manually
172bcce9bc1SSeongJae Park * entered by the user, probably inside the kdamond callbacks. Otherwise,
173bcce9bc1SSeongJae Park * DAMON sets @current_value with self-measured value of @metric.
174106e26fcSSeongJae Park */
175106e26fcSSeongJae Park struct damos_quota_goal {
176bcce9bc1SSeongJae Park enum damos_quota_goal_metric metric;
17706ba5b30SSeongJae Park unsigned long target_value;
17806ba5b30SSeongJae Park unsigned long current_value;
1792dbb60f7SSeongJae Park /* metric-dependent fields */
1802dbb60f7SSeongJae Park union {
1812dbb60f7SSeongJae Park u64 last_psi_total;
1822dbb60f7SSeongJae Park };
18391f21216SSeongJae Park struct list_head list;
184106e26fcSSeongJae Park };
185106e26fcSSeongJae Park
186106e26fcSSeongJae Park /**
1872b8a248dSSeongJae Park * struct damos_quota - Controls the aggressiveness of the given scheme.
1884d791a0aSSeongJae Park * @reset_interval: Charge reset interval in milliseconds.
1891cd24303SSeongJae Park * @ms: Maximum milliseconds that the scheme can use.
1902b8a248dSSeongJae Park * @sz: Maximum bytes of memory that the action can be applied.
19191f21216SSeongJae Park * @goals: Head of quota tuning goals (&damos_quota_goal) list.
1924d791a0aSSeongJae Park * @esz: Effective size quota in bytes.
1932b8a248dSSeongJae Park *
19438683e00SSeongJae Park * @weight_sz: Weight of the region's size for prioritization.
19538683e00SSeongJae Park * @weight_nr_accesses: Weight of the region's nr_accesses for prioritization.
19638683e00SSeongJae Park * @weight_age: Weight of the region's age for prioritization.
19738683e00SSeongJae Park *
1982b8a248dSSeongJae Park * To avoid consuming too much CPU time or IO resources for applying the
1991cd24303SSeongJae Park * &struct damos->action to large memory, DAMON allows users to set time and/or
2001cd24303SSeongJae Park * size quotas. The quotas can be set by writing non-zero values to &ms and
2011cd24303SSeongJae Park * &sz, respectively. If the time quota is set, DAMON tries to use only up to
2021cd24303SSeongJae Park * &ms milliseconds within &reset_interval for applying the action. If the
2031cd24303SSeongJae Park * size quota is set, DAMON tries to apply the action only up to &sz bytes
2041cd24303SSeongJae Park * within &reset_interval.
2051cd24303SSeongJae Park *
206d783cc59SSeongJae Park * To convince the different types of quotas and goals, DAMON internally
207d783cc59SSeongJae Park * converts those into one single size quota called "effective quota". DAMON
208d783cc59SSeongJae Park * internally uses it as the only one real quota. The conversion is made as
209d783cc59SSeongJae Park * follows.
21038683e00SSeongJae Park *
211d783cc59SSeongJae Park * The time quota is transformed to a size quota using estimated throughput of
212d783cc59SSeongJae Park * the scheme's action. DAMON then compares it against &sz and uses smaller
213d783cc59SSeongJae Park * one as the effective quota.
214d783cc59SSeongJae Park *
215d783cc59SSeongJae Park * If @goals is not empty, DAMON calculates yet another size quota based on the
21689d347a5SSeongJae Park * goals using its internal feedback loop algorithm, for every @reset_interval.
21789d347a5SSeongJae Park * Then, if the new size quota is smaller than the effective quota, it uses the
21889d347a5SSeongJae Park * new size quota as the effective quota.
21991f21216SSeongJae Park *
22078f2f603SSeongJae Park * The resulting effective size quota in bytes is set to @esz.
2214d791a0aSSeongJae Park *
2224d791a0aSSeongJae Park * For selecting regions within the quota, DAMON prioritizes current scheme's
2234d791a0aSSeongJae Park * target memory regions using the &struct damon_operations->get_scheme_score.
2244d791a0aSSeongJae Park * You could customize the prioritization logic by setting &weight_sz,
2254d791a0aSSeongJae Park * &weight_nr_accesses, and &weight_age, because monitoring operations are
2264d791a0aSSeongJae Park * encouraged to respect those.
2272b8a248dSSeongJae Park */
2282b8a248dSSeongJae Park struct damos_quota {
2294d791a0aSSeongJae Park unsigned long reset_interval;
2301cd24303SSeongJae Park unsigned long ms;
2312b8a248dSSeongJae Park unsigned long sz;
23291f21216SSeongJae Park struct list_head goals;
2334d791a0aSSeongJae Park unsigned long esz;
2342b8a248dSSeongJae Park
23538683e00SSeongJae Park unsigned int weight_sz;
23638683e00SSeongJae Park unsigned int weight_nr_accesses;
23738683e00SSeongJae Park unsigned int weight_age;
23838683e00SSeongJae Park
2391cd24303SSeongJae Park /* private: */
2401cd24303SSeongJae Park /* For throughput estimation */
2411cd24303SSeongJae Park unsigned long total_charged_sz;
2421cd24303SSeongJae Park unsigned long total_charged_ns;
2431cd24303SSeongJae Park
2441cd24303SSeongJae Park /* For charging the quota */
2452b8a248dSSeongJae Park unsigned long charged_sz;
2462b8a248dSSeongJae Park unsigned long charged_from;
24750585192SSeongJae Park struct damon_target *charge_target_from;
24850585192SSeongJae Park unsigned long charge_addr_from;
24938683e00SSeongJae Park
25038683e00SSeongJae Park /* For prioritization */
25138683e00SSeongJae Park unsigned int min_score;
2529294a037SSeongJae Park
2539294a037SSeongJae Park /* For feedback loop */
2549294a037SSeongJae Park unsigned long esz_bp;
2552b8a248dSSeongJae Park };
2562b8a248dSSeongJae Park
2572b8a248dSSeongJae Park /**
258ee801b7dSSeongJae Park * enum damos_wmark_metric - Represents the watermark metric.
259ee801b7dSSeongJae Park *
260ee801b7dSSeongJae Park * @DAMOS_WMARK_NONE: Ignore the watermarks of the given scheme.
261ee801b7dSSeongJae Park * @DAMOS_WMARK_FREE_MEM_RATE: Free memory rate of the system in [0,1000].
2625257f36eSSeongJae Park * @NR_DAMOS_WMARK_METRICS: Total number of DAMOS watermark metrics
263ee801b7dSSeongJae Park */
264ee801b7dSSeongJae Park enum damos_wmark_metric {
265ee801b7dSSeongJae Park DAMOS_WMARK_NONE,
266ee801b7dSSeongJae Park DAMOS_WMARK_FREE_MEM_RATE,
2675257f36eSSeongJae Park NR_DAMOS_WMARK_METRICS,
268ee801b7dSSeongJae Park };
269ee801b7dSSeongJae Park
270ee801b7dSSeongJae Park /**
271ee801b7dSSeongJae Park * struct damos_watermarks - Controls when a given scheme should be activated.
272ee801b7dSSeongJae Park * @metric: Metric for the watermarks.
273ee801b7dSSeongJae Park * @interval: Watermarks check time interval in microseconds.
274ee801b7dSSeongJae Park * @high: High watermark.
275ee801b7dSSeongJae Park * @mid: Middle watermark.
276ee801b7dSSeongJae Park * @low: Low watermark.
277ee801b7dSSeongJae Park *
278ee801b7dSSeongJae Park * If &metric is &DAMOS_WMARK_NONE, the scheme is always active. Being active
279ee801b7dSSeongJae Park * means DAMON does monitoring and applying the action of the scheme to
280ee801b7dSSeongJae Park * appropriate memory regions. Else, DAMON checks &metric of the system for at
281ee801b7dSSeongJae Park * least every &interval microseconds and works as below.
282ee801b7dSSeongJae Park *
283ee801b7dSSeongJae Park * If &metric is higher than &high, the scheme is inactivated. If &metric is
284ee801b7dSSeongJae Park * between &mid and &low, the scheme is activated. If &metric is lower than
285ee801b7dSSeongJae Park * &low, the scheme is inactivated.
286ee801b7dSSeongJae Park */
287ee801b7dSSeongJae Park struct damos_watermarks {
288ee801b7dSSeongJae Park enum damos_wmark_metric metric;
289ee801b7dSSeongJae Park unsigned long interval;
290ee801b7dSSeongJae Park unsigned long high;
291ee801b7dSSeongJae Park unsigned long mid;
292ee801b7dSSeongJae Park unsigned long low;
293ee801b7dSSeongJae Park
294ee801b7dSSeongJae Park /* private: */
295ee801b7dSSeongJae Park bool activated;
296ee801b7dSSeongJae Park };
297ee801b7dSSeongJae Park
298ee801b7dSSeongJae Park /**
2990e92c2eeSSeongJae Park * struct damos_stat - Statistics on a given scheme.
3000e92c2eeSSeongJae Park * @nr_tried: Total number of regions that the scheme is tried to be applied.
3010e92c2eeSSeongJae Park * @sz_tried: Total size of regions that the scheme is tried to be applied.
3020e92c2eeSSeongJae Park * @nr_applied: Total number of regions that the scheme is applied.
3030e92c2eeSSeongJae Park * @sz_applied: Total size of regions that the scheme is applied.
30460fa9355SSeongJae Park * @sz_ops_filter_passed:
30560fa9355SSeongJae Park * Total bytes that passed ops layer-handled DAMOS filters.
3066268eac3SSeongJae Park * @qt_exceeds: Total number of times the quota of the scheme has exceeded.
307626ffabeSSeongJae Park *
308626ffabeSSeongJae Park * "Tried an action to a region" in this context means the DAMOS core logic
309626ffabeSSeongJae Park * determined the region as eligible to apply the action. The access pattern
310626ffabeSSeongJae Park * (&struct damos_access_pattern), quotas (&struct damos_quota), watermarks
311626ffabeSSeongJae Park * (&struct damos_watermarks) and filters (&struct damos_filter) that handled
312626ffabeSSeongJae Park * on core logic can affect this. The core logic asks the operation set
313626ffabeSSeongJae Park * (&struct damon_operations) to apply the action to the region.
314626ffabeSSeongJae Park *
315626ffabeSSeongJae Park * "Applied an action to a region" in this context means the operation set
316626ffabeSSeongJae Park * (&struct damon_operations) successfully applied the action to the region, at
317626ffabeSSeongJae Park * least to a part of the region. The filters (&struct damos_filter) that
318626ffabeSSeongJae Park * handled on operation set layer and type of the action and pages of the
319626ffabeSSeongJae Park * region can affect this. For example, if a filter is set to exclude
320626ffabeSSeongJae Park * anonymous pages and the region has only anonymous pages, the region will be
321626ffabeSSeongJae Park * failed at applying the action. If the action is &DAMOS_PAGEOUT and all
322626ffabeSSeongJae Park * pages of the region are already paged out, the region will be failed at
323626ffabeSSeongJae Park * applying the action.
3240e92c2eeSSeongJae Park */
3250e92c2eeSSeongJae Park struct damos_stat {
3260e92c2eeSSeongJae Park unsigned long nr_tried;
3270e92c2eeSSeongJae Park unsigned long sz_tried;
3280e92c2eeSSeongJae Park unsigned long nr_applied;
3290e92c2eeSSeongJae Park unsigned long sz_applied;
33060fa9355SSeongJae Park unsigned long sz_ops_filter_passed;
3316268eac3SSeongJae Park unsigned long qt_exceeds;
3320e92c2eeSSeongJae Park };
3330e92c2eeSSeongJae Park
3340e92c2eeSSeongJae Park /**
33598def236SSeongJae Park * enum damos_filter_type - Type of memory for &struct damos_filter
33698def236SSeongJae Park * @DAMOS_FILTER_TYPE_ANON: Anonymous pages.
337*3b23a44fSNhat Pham * @DAMOS_FILTER_TYPE_ACTIVE: Active pages.
33898def236SSeongJae Park * @DAMOS_FILTER_TYPE_MEMCG: Specific memcg's pages.
3392d8b2465SSeongJae Park * @DAMOS_FILTER_TYPE_YOUNG: Recently accessed pages.
3400431c426SUsama Arif * @DAMOS_FILTER_TYPE_HUGEPAGE_SIZE: Page is part of a hugepage.
341f809b9f3SSeongJae Park * @DAMOS_FILTER_TYPE_UNMAPPED: Unmapped pages.
342ab9bda00SSeongJae Park * @DAMOS_FILTER_TYPE_ADDR: Address range.
34317e7c724SSeongJae Park * @DAMOS_FILTER_TYPE_TARGET: Data Access Monitoring target.
34498def236SSeongJae Park * @NR_DAMOS_FILTER_TYPES: Number of filter types.
34555901e89SSeongJae Park *
346ab9bda00SSeongJae Park * The anon pages type and memcg type filters are handled by underlying
347ab9bda00SSeongJae Park * &struct damon_operations as a part of scheme action trying, and therefore
348ab9bda00SSeongJae Park * accounted as 'tried'. In contrast, other types are handled by core layer
349ab9bda00SSeongJae Park * before trying of the action and therefore not accounted as 'tried'.
350ab9bda00SSeongJae Park *
351ab9bda00SSeongJae Park * The support of the filters that handled by &struct damon_operations depend
352ab9bda00SSeongJae Park * on the running &struct damon_operations.
353ab9bda00SSeongJae Park * &enum DAMON_OPS_PADDR supports both anon pages type and memcg type filters,
354ab9bda00SSeongJae Park * while &enum DAMON_OPS_VADDR and &enum DAMON_OPS_FVADDR don't support any of
355ab9bda00SSeongJae Park * the two types.
35698def236SSeongJae Park */
35798def236SSeongJae Park enum damos_filter_type {
35898def236SSeongJae Park DAMOS_FILTER_TYPE_ANON,
359*3b23a44fSNhat Pham DAMOS_FILTER_TYPE_ACTIVE,
36098def236SSeongJae Park DAMOS_FILTER_TYPE_MEMCG,
3612d8b2465SSeongJae Park DAMOS_FILTER_TYPE_YOUNG,
3620431c426SUsama Arif DAMOS_FILTER_TYPE_HUGEPAGE_SIZE,
363f809b9f3SSeongJae Park DAMOS_FILTER_TYPE_UNMAPPED,
364ab9bda00SSeongJae Park DAMOS_FILTER_TYPE_ADDR,
36517e7c724SSeongJae Park DAMOS_FILTER_TYPE_TARGET,
36698def236SSeongJae Park NR_DAMOS_FILTER_TYPES,
36798def236SSeongJae Park };
36898def236SSeongJae Park
36998def236SSeongJae Park /**
37098def236SSeongJae Park * struct damos_filter - DAMOS action target memory filter.
371e20f52e8SSeongJae Park * @type: Type of the target memory.
372fe6d7fddSSeongJae Park * @matching: Whether this is for @type-matching memory.
373fe6d7fddSSeongJae Park * @allow: Whether to include or exclude the @matching memory.
37498def236SSeongJae Park * @memcg_id: Memcg id of the question if @type is DAMOS_FILTER_MEMCG.
375ab9bda00SSeongJae Park * @addr_range: Address range if @type is DAMOS_FILTER_TYPE_ADDR.
37617e7c724SSeongJae Park * @target_idx: Index of the &struct damon_target of
37717e7c724SSeongJae Park * &damon_ctx->adaptive_targets if @type is
37817e7c724SSeongJae Park * DAMOS_FILTER_TYPE_TARGET.
3790431c426SUsama Arif * @sz_range: Size range if @type is DAMOS_FILTER_TYPE_HUGEPAGE_SIZE.
38098def236SSeongJae Park * @list: List head for siblings.
38198def236SSeongJae Park *
38298def236SSeongJae Park * Before applying the &damos->action to a memory region, DAMOS checks if each
383e20f52e8SSeongJae Park * byte of the region matches to this given condition and avoid applying the
384e20f52e8SSeongJae Park * action if so. Support of each filter type depends on the running &struct
385e20f52e8SSeongJae Park * damon_operations and the type. Refer to &enum damos_filter_type for more
386e20f52e8SSeongJae Park * details.
38798def236SSeongJae Park */
38898def236SSeongJae Park struct damos_filter {
38998def236SSeongJae Park enum damos_filter_type type;
39098def236SSeongJae Park bool matching;
391fe6d7fddSSeongJae Park bool allow;
39298def236SSeongJae Park union {
39398def236SSeongJae Park unsigned short memcg_id;
394ab9bda00SSeongJae Park struct damon_addr_range addr_range;
39517e7c724SSeongJae Park int target_idx;
3960431c426SUsama Arif struct damon_size_range sz_range;
39798def236SSeongJae Park };
39898def236SSeongJae Park struct list_head list;
39998def236SSeongJae Park };
40098def236SSeongJae Park
401bf0eaba0SSeongJae Park struct damon_ctx;
402bf0eaba0SSeongJae Park struct damos;
403bf0eaba0SSeongJae Park
404bf0eaba0SSeongJae Park /**
405bf0eaba0SSeongJae Park * struct damos_walk_control - Control damos_walk().
406bf0eaba0SSeongJae Park *
407bf0eaba0SSeongJae Park * @walk_fn: Function to be called back for each region.
408bf0eaba0SSeongJae Park * @data: Data that will be passed to walk functions.
409bf0eaba0SSeongJae Park *
410bf0eaba0SSeongJae Park * Control damos_walk(), which requests specific kdamond to invoke the given
411bf0eaba0SSeongJae Park * function to each region that eligible to apply actions of the kdamond's
412bf0eaba0SSeongJae Park * schemes. Refer to damos_walk() for more details.
413bf0eaba0SSeongJae Park */
414bf0eaba0SSeongJae Park struct damos_walk_control {
415bf0eaba0SSeongJae Park void (*walk_fn)(void *data, struct damon_ctx *ctx,
416bf0eaba0SSeongJae Park struct damon_target *t, struct damon_region *r,
417cfc33a7dSSeongJae Park struct damos *s, unsigned long sz_filter_passed);
418bf0eaba0SSeongJae Park void *data;
419bf0eaba0SSeongJae Park /* private: internal use only */
420bf0eaba0SSeongJae Park /* informs if the kdamond finished handling of the walk request */
421bf0eaba0SSeongJae Park struct completion completion;
422bf0eaba0SSeongJae Park /* informs if the walk is canceled. */
423bf0eaba0SSeongJae Park bool canceled;
424bf0eaba0SSeongJae Park };
425bf0eaba0SSeongJae Park
42698def236SSeongJae Park /**
427f5a79d7cSYajun Deng * struct damos_access_pattern - Target access pattern of the given scheme.
4281f366e42SSeongJae Park * @min_sz_region: Minimum size of target regions.
4291f366e42SSeongJae Park * @max_sz_region: Maximum size of target regions.
4301f366e42SSeongJae Park * @min_nr_accesses: Minimum ``->nr_accesses`` of target regions.
4311f366e42SSeongJae Park * @max_nr_accesses: Maximum ``->nr_accesses`` of target regions.
4321f366e42SSeongJae Park * @min_age_region: Minimum age of target regions.
4331f366e42SSeongJae Park * @max_age_region: Maximum age of target regions.
434f5a79d7cSYajun Deng */
435f5a79d7cSYajun Deng struct damos_access_pattern {
436f5a79d7cSYajun Deng unsigned long min_sz_region;
437f5a79d7cSYajun Deng unsigned long max_sz_region;
438f5a79d7cSYajun Deng unsigned int min_nr_accesses;
439f5a79d7cSYajun Deng unsigned int max_nr_accesses;
440f5a79d7cSYajun Deng unsigned int min_age_region;
441f5a79d7cSYajun Deng unsigned int max_age_region;
442f5a79d7cSYajun Deng };
443f5a79d7cSYajun Deng
444f5a79d7cSYajun Deng /**
445f5a79d7cSYajun Deng * struct damos - Represents a Data Access Monitoring-based Operation Scheme.
446f5a79d7cSYajun Deng * @pattern: Access pattern of target regions.
4471f366e42SSeongJae Park * @action: &damo_action to be applied to the target regions.
44842f994b7SSeongJae Park * @apply_interval_us: The time between applying the @action.
4492b8a248dSSeongJae Park * @quota: Control the aggressiveness of this scheme.
450ee801b7dSSeongJae Park * @wmarks: Watermarks for automated (in)activation of this scheme.
451e36287c6SHyeongtak Ji * @target_nid: Destination node if @action is "migrate_{hot,cold}".
45298def236SSeongJae Park * @filters: Additional set of &struct damos_filter for &action.
453ab82e579SSeongJae Park * @ops_filters: ops layer handling &struct damos_filter objects list.
45494ba17adSSeongJae Park * @last_applied: Last @action applied ops-managing entity.
4550e92c2eeSSeongJae Park * @stat: Statistics of this scheme.
4561f366e42SSeongJae Park * @list: List head for siblings.
4571f366e42SSeongJae Park *
45842f994b7SSeongJae Park * For each @apply_interval_us, DAMON finds regions which fit in the
459f5a79d7cSYajun Deng * &pattern and applies &action to those. To avoid consuming too much
460f5a79d7cSYajun Deng * CPU time or IO resources for the &action, "a is used.
4612b8a248dSSeongJae Park *
46242f994b7SSeongJae Park * If @apply_interval_us is zero, &damon_attrs->aggr_interval is used instead.
46342f994b7SSeongJae Park *
464ee801b7dSSeongJae Park * To do the work only when needed, schemes can be activated for specific
465ee801b7dSSeongJae Park * system situations using &wmarks. If all schemes that registered to the
466ee801b7dSSeongJae Park * monitoring context are inactive, DAMON stops monitoring either, and just
467ee801b7dSSeongJae Park * repeatedly checks the watermarks.
468ee801b7dSSeongJae Park *
469e36287c6SHyeongtak Ji * @target_nid is used to set the migration target node for migrate_hot or
470e36287c6SHyeongtak Ji * migrate_cold actions, which means it's only meaningful when @action is either
471e36287c6SHyeongtak Ji * "migrate_hot" or "migrate_cold".
472e36287c6SHyeongtak Ji *
47398def236SSeongJae Park * Before applying the &action to a memory region, &struct damon_operations
47498def236SSeongJae Park * implementation could check pages of the region and skip &action to respect
47598def236SSeongJae Park * &filters
47698def236SSeongJae Park *
47794ba17adSSeongJae Park * The minimum entity that @action can be applied depends on the underlying
47894ba17adSSeongJae Park * &struct damon_operations. Since it may not be aligned with the core layer
47994ba17adSSeongJae Park * abstract, namely &struct damon_region, &struct damon_operations could apply
48094ba17adSSeongJae Park * @action to same entity multiple times. Large folios that underlying on
48194ba17adSSeongJae Park * multiple &struct damon region objects could be such examples. The &struct
48294ba17adSSeongJae Park * damon_operations can use @last_applied to avoid that. DAMOS core logic
48394ba17adSSeongJae Park * unsets @last_applied when each regions walking for applying the scheme is
48494ba17adSSeongJae Park * finished.
48594ba17adSSeongJae Park *
4862b8a248dSSeongJae Park * After applying the &action to each region, &stat_count and &stat_sz is
4872b8a248dSSeongJae Park * updated to reflect the number of regions and total size of regions that the
4882b8a248dSSeongJae Park * &action is applied.
4891f366e42SSeongJae Park */
4901f366e42SSeongJae Park struct damos {
491f5a79d7cSYajun Deng struct damos_access_pattern pattern;
4921f366e42SSeongJae Park enum damos_action action;
49342f994b7SSeongJae Park unsigned long apply_interval_us;
49442f994b7SSeongJae Park /* private: internal use only */
49542f994b7SSeongJae Park /*
49642f994b7SSeongJae Park * number of sample intervals that should be passed before applying
49742f994b7SSeongJae Park * @action
49842f994b7SSeongJae Park */
49942f994b7SSeongJae Park unsigned long next_apply_sis;
500bf0eaba0SSeongJae Park /* informs if ongoing DAMOS walk for this scheme is finished */
501bf0eaba0SSeongJae Park bool walk_completed;
50239a326e6SSeongJae Park /*
50339a326e6SSeongJae Park * If the current region in the filtering stage is allowed by core
50439a326e6SSeongJae Park * layer-handled filters. If true, operations layer allows it, too.
50539a326e6SSeongJae Park */
50639a326e6SSeongJae Park bool core_filters_allowed;
507dd038b72SSeongJae Park /* whether to reject core/ops filters umatched regions */
508dd038b72SSeongJae Park bool core_filters_default_reject;
509dd038b72SSeongJae Park bool ops_filters_default_reject;
51042f994b7SSeongJae Park /* public: */
5112b8a248dSSeongJae Park struct damos_quota quota;
512ee801b7dSSeongJae Park struct damos_watermarks wmarks;
513e36287c6SHyeongtak Ji union {
514e36287c6SHyeongtak Ji int target_nid;
515e36287c6SHyeongtak Ji };
51698def236SSeongJae Park struct list_head filters;
517ab82e579SSeongJae Park struct list_head ops_filters;
51894ba17adSSeongJae Park void *last_applied;
5190e92c2eeSSeongJae Park struct damos_stat stat;
5201f366e42SSeongJae Park struct list_head list;
5211f366e42SSeongJae Park };
5221f366e42SSeongJae Park
5239f7b053aSSeongJae Park /**
5249f7b053aSSeongJae Park * enum damon_ops_id - Identifier for each monitoring operations implementation
5259f7b053aSSeongJae Park *
5269f7b053aSSeongJae Park * @DAMON_OPS_VADDR: Monitoring operations for virtual address spaces
527de6d0154SSeongJae Park * @DAMON_OPS_FVADDR: Monitoring operations for only fixed ranges of virtual
528de6d0154SSeongJae Park * address spaces
5299f7b053aSSeongJae Park * @DAMON_OPS_PADDR: Monitoring operations for the physical address space
530d4a157f5SGautam Menghani * @NR_DAMON_OPS: Number of monitoring operations implementations
5319f7b053aSSeongJae Park */
5329f7b053aSSeongJae Park enum damon_ops_id {
5339f7b053aSSeongJae Park DAMON_OPS_VADDR,
534de6d0154SSeongJae Park DAMON_OPS_FVADDR,
5359f7b053aSSeongJae Park DAMON_OPS_PADDR,
5369f7b053aSSeongJae Park NR_DAMON_OPS,
5379f7b053aSSeongJae Park };
5389f7b053aSSeongJae Park
5392224d848SSeongJae Park /**
540f7d911c3SSeongJae Park * struct damon_operations - Monitoring operations for given use cases.
5412224d848SSeongJae Park *
5429f7b053aSSeongJae Park * @id: Identifier of this operations set.
543f7d911c3SSeongJae Park * @init: Initialize operations-related data structures.
544f7d911c3SSeongJae Park * @update: Update operations-related data structures.
5452224d848SSeongJae Park * @prepare_access_checks: Prepare next access check of target regions.
5462224d848SSeongJae Park * @check_accesses: Check the accesses to target regions.
54738683e00SSeongJae Park * @get_scheme_score: Get the score of a region for a scheme.
5481f366e42SSeongJae Park * @apply_scheme: Apply a DAMON-based operation scheme.
5492224d848SSeongJae Park * @target_valid: Determine if the target is valid.
5502224d848SSeongJae Park * @cleanup: Clean up the context.
5512224d848SSeongJae Park *
5522224d848SSeongJae Park * DAMON can be extended for various address spaces and usages. For this,
553f7d911c3SSeongJae Park * users should register the low level operations for their target address
554f7d911c3SSeongJae Park * space and usecase via the &damon_ctx.ops. Then, the monitoring thread
5552224d848SSeongJae Park * (&damon_ctx.kdamond) calls @init and @prepare_access_checks before starting
5566b3f013bSSeongJae Park * the monitoring, @update after each &damon_attrs.ops_update_interval, and
5572224d848SSeongJae Park * @check_accesses, @target_valid and @prepare_access_checks after each
558105f830fSSeongJae Park * &damon_attrs.sample_interval.
5592224d848SSeongJae Park *
5609f7b053aSSeongJae Park * Each &struct damon_operations instance having valid @id can be registered
5619f7b053aSSeongJae Park * via damon_register_ops() and selected by damon_select_ops() later.
562f7d911c3SSeongJae Park * @init should initialize operations-related data structures. For example,
5632224d848SSeongJae Park * this could be used to construct proper monitoring target regions and link
564f23b8eeeSSeongJae Park * those to @damon_ctx.adaptive_targets.
565f7d911c3SSeongJae Park * @update should update the operations-related data structures. For example,
5662224d848SSeongJae Park * this could be used to update monitoring target regions for current status.
5672224d848SSeongJae Park * @prepare_access_checks should manipulate the monitoring regions to be
5682224d848SSeongJae Park * prepared for the next access check.
5692224d848SSeongJae Park * @check_accesses should check the accesses to each region that made after the
5702224d848SSeongJae Park * last preparation and update the number of observed accesses of each region.
571b9a6ac4eSSeongJae Park * It should also return max number of observed accesses that made as a result
572b9a6ac4eSSeongJae Park * of its update. The value will be used for regions adjustment threshold.
57338683e00SSeongJae Park * @get_scheme_score should return the priority score of a region for a scheme
57438683e00SSeongJae Park * as an integer in [0, &DAMOS_MAX_SCORE].
5751f366e42SSeongJae Park * @apply_scheme is called from @kdamond when a region for user provided
5761f366e42SSeongJae Park * DAMON-based operation scheme is found. It should apply the scheme's action
5770e92c2eeSSeongJae Park * to the region and return bytes of the region that the action is successfully
578b5bbe9c0SSeongJae Park * applied. It should also report how many bytes of the region has passed
579b5bbe9c0SSeongJae Park * filters (&struct damos_filter) that handled by itself.
5802224d848SSeongJae Park * @target_valid should check whether the target is still valid for the
5812224d848SSeongJae Park * monitoring.
5822224d848SSeongJae Park * @cleanup is called from @kdamond just before its termination.
5832224d848SSeongJae Park */
584f7d911c3SSeongJae Park struct damon_operations {
5859f7b053aSSeongJae Park enum damon_ops_id id;
5862224d848SSeongJae Park void (*init)(struct damon_ctx *context);
5872224d848SSeongJae Park void (*update)(struct damon_ctx *context);
5882224d848SSeongJae Park void (*prepare_access_checks)(struct damon_ctx *context);
589b9a6ac4eSSeongJae Park unsigned int (*check_accesses)(struct damon_ctx *context);
59038683e00SSeongJae Park int (*get_scheme_score)(struct damon_ctx *context,
59138683e00SSeongJae Park struct damon_target *t, struct damon_region *r,
59238683e00SSeongJae Park struct damos *scheme);
5930e92c2eeSSeongJae Park unsigned long (*apply_scheme)(struct damon_ctx *context,
5940e92c2eeSSeongJae Park struct damon_target *t, struct damon_region *r,
595b5bbe9c0SSeongJae Park struct damos *scheme, unsigned long *sz_filter_passed);
59616bc1b0fSKaixu Xia bool (*target_valid)(struct damon_target *t);
5972224d848SSeongJae Park void (*cleanup)(struct damon_ctx *context);
5982224d848SSeongJae Park };
5992224d848SSeongJae Park
600d2f272b3SSeongJae Park /**
601d2f272b3SSeongJae Park * struct damon_callback - Monitoring events notification callbacks.
6022224d848SSeongJae Park *
6036e74d2bfSSeongJae Park * @after_wmarks_check: Called after each schemes' watermarks check.
6042224d848SSeongJae Park * @after_aggregation: Called after each aggregation.
6052224d848SSeongJae Park * @before_terminate: Called before terminating the monitoring.
6062224d848SSeongJae Park *
60707da2185SSeongJae Park * The monitoring thread (&damon_ctx.kdamond) calls @before_terminate just
60807da2185SSeongJae Park * before finishing the monitoring.
6092224d848SSeongJae Park *
6106e74d2bfSSeongJae Park * The monitoring thread calls @after_wmarks_check after each DAMON-based
6116e74d2bfSSeongJae Park * operation schemes' watermarks check. If users need to make changes to the
6126e74d2bfSSeongJae Park * attributes of the monitoring context while it's deactivated due to the
6136e74d2bfSSeongJae Park * watermarks, this is the good place to do.
6146e74d2bfSSeongJae Park *
615cedee98fSSeongJae Park * The monitoring thread calls @after_aggregation for each of the aggregation
616cedee98fSSeongJae Park * intervals. Therefore, users can safely access the monitoring results
617cedee98fSSeongJae Park * without additional protection. For the reason, users are recommended to use
618cedee98fSSeongJae Park * these callback for the accesses to the results.
6192224d848SSeongJae Park *
6202224d848SSeongJae Park * If any callback returns non-zero, monitoring stops.
6212224d848SSeongJae Park */
6222224d848SSeongJae Park struct damon_callback {
6236e74d2bfSSeongJae Park int (*after_wmarks_check)(struct damon_ctx *context);
6242224d848SSeongJae Park int (*after_aggregation)(struct damon_ctx *context);
625658f9ae7SChangbin Du void (*before_terminate)(struct damon_ctx *context);
6262224d848SSeongJae Park };
6272224d848SSeongJae Park
62842b7491aSSeongJae Park /*
62942b7491aSSeongJae Park * struct damon_call_control - Control damon_call().
63042b7491aSSeongJae Park *
63142b7491aSSeongJae Park * @fn: Function to be called back.
63242b7491aSSeongJae Park * @data: Data that will be passed to @fn.
63342b7491aSSeongJae Park * @return_code: Return code from @fn invocation.
63442b7491aSSeongJae Park *
63542b7491aSSeongJae Park * Control damon_call(), which requests specific kdamond to invoke a given
63642b7491aSSeongJae Park * function. Refer to damon_call() for more details.
63742b7491aSSeongJae Park */
63842b7491aSSeongJae Park struct damon_call_control {
63942b7491aSSeongJae Park int (*fn)(void *data);
64042b7491aSSeongJae Park void *data;
64142b7491aSSeongJae Park int return_code;
64242b7491aSSeongJae Park /* private: internal use only */
64342b7491aSSeongJae Park /* informs if the kdamond finished handling of the request */
64442b7491aSSeongJae Park struct completion completion;
64542b7491aSSeongJae Park /* informs if the kdamond canceled @fn infocation */
64642b7491aSSeongJae Park bool canceled;
64742b7491aSSeongJae Park };
64842b7491aSSeongJae Park
6492224d848SSeongJae Park /**
6501eb3471bSSeongJae Park * struct damon_intervals_goal - Monitoring intervals auto-tuning goal.
6511eb3471bSSeongJae Park *
6521eb3471bSSeongJae Park * @access_bp: Access events observation ratio to achieve in bp.
6531eb3471bSSeongJae Park * @aggrs: Number of aggregations to acheive @access_bp within.
6541eb3471bSSeongJae Park * @min_sample_us: Minimum resulting sampling interval in microseconds.
6551eb3471bSSeongJae Park * @max_sample_us: Maximum resulting sampling interval in microseconds.
6561eb3471bSSeongJae Park *
6571eb3471bSSeongJae Park * DAMON automatically tunes &damon_attrs->sample_interval and
6581eb3471bSSeongJae Park * &damon_attrs->aggr_interval aiming the ratio in bp (1/10,000) of
6591eb3471bSSeongJae Park * DAMON-observed access events to theoretical maximum amount within @aggrs
6601eb3471bSSeongJae Park * aggregations be same to @access_bp. The logic increases
6611eb3471bSSeongJae Park * &damon_attrs->aggr_interval and &damon_attrs->sampling_interval in same
6621eb3471bSSeongJae Park * ratio if the current access events observation ratio is lower than the
6631eb3471bSSeongJae Park * target for each @aggrs aggregations, and vice versa.
6641eb3471bSSeongJae Park *
6651eb3471bSSeongJae Park * If @aggrs is zero, the tuning is disabled and hence this struct is ignored.
6661eb3471bSSeongJae Park */
6671eb3471bSSeongJae Park struct damon_intervals_goal {
6681eb3471bSSeongJae Park unsigned long access_bp;
6691eb3471bSSeongJae Park unsigned long aggrs;
6701eb3471bSSeongJae Park unsigned long min_sample_us;
6711eb3471bSSeongJae Park unsigned long max_sample_us;
6721eb3471bSSeongJae Park };
6731eb3471bSSeongJae Park
6741eb3471bSSeongJae Park /**
675cbeaa77bSSeongJae Park * struct damon_attrs - Monitoring attributes for accuracy/overhead control.
6762224d848SSeongJae Park *
6772224d848SSeongJae Park * @sample_interval: The time between access samplings.
6782224d848SSeongJae Park * @aggr_interval: The time between monitor results aggregations.
679f7d911c3SSeongJae Park * @ops_update_interval: The time between monitoring operations updates.
6801eb3471bSSeongJae Park * @intervals_goal: Intervals auto-tuning goal.
681cbeaa77bSSeongJae Park * @min_nr_regions: The minimum number of adaptive monitoring
682cbeaa77bSSeongJae Park * regions.
683cbeaa77bSSeongJae Park * @max_nr_regions: The maximum number of adaptive monitoring
684cbeaa77bSSeongJae Park * regions.
6852224d848SSeongJae Park *
6862224d848SSeongJae Park * For each @sample_interval, DAMON checks whether each region is accessed or
687d896073fSSeongJae Park * not during the last @sample_interval. If such access is found, DAMON
688d896073fSSeongJae Park * aggregates the information by increasing &damon_region->nr_accesses for
689d896073fSSeongJae Park * @aggr_interval time. For each @aggr_interval, the count is reset. DAMON
690d896073fSSeongJae Park * also checks whether the target memory regions need update (e.g., by
691d896073fSSeongJae Park * ``mmap()`` calls from the application, in case of virtual memory monitoring)
692d896073fSSeongJae Park * and applies the changes for each @ops_update_interval. All time intervals
693d896073fSSeongJae Park * are in micro-seconds. Please refer to &struct damon_operations and &struct
694d896073fSSeongJae Park * damon_callback for more detail.
695cbeaa77bSSeongJae Park */
696cbeaa77bSSeongJae Park struct damon_attrs {
697cbeaa77bSSeongJae Park unsigned long sample_interval;
698cbeaa77bSSeongJae Park unsigned long aggr_interval;
699cbeaa77bSSeongJae Park unsigned long ops_update_interval;
7001eb3471bSSeongJae Park struct damon_intervals_goal intervals_goal;
701cbeaa77bSSeongJae Park unsigned long min_nr_regions;
702cbeaa77bSSeongJae Park unsigned long max_nr_regions;
703f04b0fedSSeongJae Park /* private: internal use only */
704f04b0fedSSeongJae Park /*
705f04b0fedSSeongJae Park * @aggr_interval to @sample_interval ratio.
706f04b0fedSSeongJae Park * Core-external components call damon_set_attrs() with &damon_attrs
707f04b0fedSSeongJae Park * that this field is unset. In the case, damon_set_attrs() sets this
708f04b0fedSSeongJae Park * field of resulting &damon_attrs. Core-internal components such as
709f04b0fedSSeongJae Park * kdamond_tune_intervals() calls damon_set_attrs() with &damon_attrs
710f04b0fedSSeongJae Park * that this field is set. In the case, damon_set_attrs() just keep
711f04b0fedSSeongJae Park * it.
712f04b0fedSSeongJae Park */
713f04b0fedSSeongJae Park unsigned long aggr_samples;
714cbeaa77bSSeongJae Park };
715cbeaa77bSSeongJae Park
716cbeaa77bSSeongJae Park /**
717cbeaa77bSSeongJae Park * struct damon_ctx - Represents a context for each monitoring. This is the
718cbeaa77bSSeongJae Park * main interface that allows users to set the attributes and get the results
719cbeaa77bSSeongJae Park * of the monitoring.
7202224d848SSeongJae Park *
721cbeaa77bSSeongJae Park * @attrs: Monitoring attributes for accuracy/overhead control.
7222224d848SSeongJae Park * @kdamond: Kernel thread who does the monitoring.
7232224d848SSeongJae Park * @kdamond_lock: Mutex for the synchronizations with @kdamond.
7242224d848SSeongJae Park *
7252224d848SSeongJae Park * For each monitoring context, one kernel thread for the monitoring is
7262224d848SSeongJae Park * created. The pointer to the thread is stored in @kdamond.
7272224d848SSeongJae Park *
7282224d848SSeongJae Park * Once started, the monitoring thread runs until explicitly required to be
7292224d848SSeongJae Park * terminated or every monitoring target is invalid. The validity of the
730f7d911c3SSeongJae Park * targets is checked via the &damon_operations.target_valid of @ops. The
731bcc728ebSChengming Zhou * termination can also be explicitly requested by calling damon_stop().
732bcc728ebSChengming Zhou * The thread sets @kdamond to NULL when it terminates. Therefore, users can
733bcc728ebSChengming Zhou * know whether the monitoring is ongoing or terminated by reading @kdamond.
734bcc728ebSChengming Zhou * Reads and writes to @kdamond from outside of the monitoring thread must
735bcc728ebSChengming Zhou * be protected by @kdamond_lock.
7362224d848SSeongJae Park *
737bcc728ebSChengming Zhou * Note that the monitoring thread protects only @kdamond via @kdamond_lock.
738bcc728ebSChengming Zhou * Accesses to other fields must be protected by themselves.
7392224d848SSeongJae Park *
740f7d911c3SSeongJae Park * @ops: Set of monitoring operations for given use cases.
7412224d848SSeongJae Park * @callback: Set of callbacks for monitoring events notifications.
7422224d848SSeongJae Park *
743b9a6ac4eSSeongJae Park * @adaptive_targets: Head of monitoring targets (&damon_target) list.
7441f366e42SSeongJae Park * @schemes: Head of schemes (&damos) list.
7452224d848SSeongJae Park */
7462224d848SSeongJae Park struct damon_ctx {
747cbeaa77bSSeongJae Park struct damon_attrs attrs;
7482224d848SSeongJae Park
7492224d848SSeongJae Park /* private: internal use only */
7504472edf6SSeongJae Park /* number of sample intervals that passed since this context started */
7514472edf6SSeongJae Park unsigned long passed_sample_intervals;
7524472edf6SSeongJae Park /*
7534472edf6SSeongJae Park * number of sample intervals that should be passed before next
7544472edf6SSeongJae Park * aggregation
7554472edf6SSeongJae Park */
7564472edf6SSeongJae Park unsigned long next_aggregation_sis;
7574472edf6SSeongJae Park /*
7584472edf6SSeongJae Park * number of sample intervals that should be passed before next ops
7594472edf6SSeongJae Park * update
7604472edf6SSeongJae Park */
7614472edf6SSeongJae Park unsigned long next_ops_update_sis;
762f04b0fedSSeongJae Park /*
763f04b0fedSSeongJae Park * number of sample intervals that should be passed before next
764f04b0fedSSeongJae Park * intervals tuning
765f04b0fedSSeongJae Park */
766f04b0fedSSeongJae Park unsigned long next_intervals_tune_sis;
7676376a824SSeongJae Park /* for waiting until the execution of the kdamond_fn is started */
7686376a824SSeongJae Park struct completion kdamond_started;
769b7315fbbSSeongJae Park /* for scheme quotas prioritization */
770b7315fbbSSeongJae Park unsigned long *regions_score_histogram;
7712224d848SSeongJae Park
77242b7491aSSeongJae Park struct damon_call_control *call_control;
77342b7491aSSeongJae Park struct mutex call_control_lock;
77442b7491aSSeongJae Park
775bf0eaba0SSeongJae Park struct damos_walk_control *walk_control;
776bf0eaba0SSeongJae Park struct mutex walk_control_lock;
777bf0eaba0SSeongJae Park
7782224d848SSeongJae Park /* public: */
7792224d848SSeongJae Park struct task_struct *kdamond;
7802224d848SSeongJae Park struct mutex kdamond_lock;
7812224d848SSeongJae Park
782f7d911c3SSeongJae Park struct damon_operations ops;
7832224d848SSeongJae Park struct damon_callback callback;
7842224d848SSeongJae Park
785b9a6ac4eSSeongJae Park struct list_head adaptive_targets;
7861f366e42SSeongJae Park struct list_head schemes;
7872224d848SSeongJae Park };
7882224d848SSeongJae Park
damon_next_region(struct damon_region * r)78988f86dcfSSeongJae Park static inline struct damon_region *damon_next_region(struct damon_region *r)
79088f86dcfSSeongJae Park {
79188f86dcfSSeongJae Park return container_of(r->list.next, struct damon_region, list);
79288f86dcfSSeongJae Park }
793f23b8eeeSSeongJae Park
damon_prev_region(struct damon_region * r)79488f86dcfSSeongJae Park static inline struct damon_region *damon_prev_region(struct damon_region *r)
79588f86dcfSSeongJae Park {
79688f86dcfSSeongJae Park return container_of(r->list.prev, struct damon_region, list);
79788f86dcfSSeongJae Park }
798f23b8eeeSSeongJae Park
damon_last_region(struct damon_target * t)79988f86dcfSSeongJae Park static inline struct damon_region *damon_last_region(struct damon_target *t)
80088f86dcfSSeongJae Park {
80188f86dcfSSeongJae Park return list_last_entry(&t->regions_list, struct damon_region, list);
80288f86dcfSSeongJae Park }
80350585192SSeongJae Park
damon_first_region(struct damon_target * t)80436001cbaSKaixu Xia static inline struct damon_region *damon_first_region(struct damon_target *t)
80536001cbaSKaixu Xia {
80636001cbaSKaixu Xia return list_first_entry(&t->regions_list, struct damon_region, list);
80736001cbaSKaixu Xia }
80836001cbaSKaixu Xia
damon_sz_region(struct damon_region * r)809652e0446SXin Hao static inline unsigned long damon_sz_region(struct damon_region *r)
810652e0446SXin Hao {
811652e0446SXin Hao return r->ar.end - r->ar.start;
812652e0446SXin Hao }
813652e0446SXin Hao
814652e0446SXin Hao
815f23b8eeeSSeongJae Park #define damon_for_each_region(r, t) \
816f23b8eeeSSeongJae Park list_for_each_entry(r, &t->regions_list, list)
817f23b8eeeSSeongJae Park
81836001cbaSKaixu Xia #define damon_for_each_region_from(r, t) \
81936001cbaSKaixu Xia list_for_each_entry_from(r, &t->regions_list, list)
82036001cbaSKaixu Xia
821f23b8eeeSSeongJae Park #define damon_for_each_region_safe(r, next, t) \
822f23b8eeeSSeongJae Park list_for_each_entry_safe(r, next, &t->regions_list, list)
823f23b8eeeSSeongJae Park
824f23b8eeeSSeongJae Park #define damon_for_each_target(t, ctx) \
825b9a6ac4eSSeongJae Park list_for_each_entry(t, &(ctx)->adaptive_targets, list)
826f23b8eeeSSeongJae Park
827f23b8eeeSSeongJae Park #define damon_for_each_target_safe(t, next, ctx) \
828b9a6ac4eSSeongJae Park list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list)
829f23b8eeeSSeongJae Park
8301f366e42SSeongJae Park #define damon_for_each_scheme(s, ctx) \
8311f366e42SSeongJae Park list_for_each_entry(s, &(ctx)->schemes, list)
8321f366e42SSeongJae Park
8331f366e42SSeongJae Park #define damon_for_each_scheme_safe(s, next, ctx) \
8341f366e42SSeongJae Park list_for_each_entry_safe(s, next, &(ctx)->schemes, list)
8351f366e42SSeongJae Park
83691f21216SSeongJae Park #define damos_for_each_quota_goal(goal, quota) \
83791f21216SSeongJae Park list_for_each_entry(goal, "a->goals, list)
83891f21216SSeongJae Park
83991f21216SSeongJae Park #define damos_for_each_quota_goal_safe(goal, next, quota) \
84091f21216SSeongJae Park list_for_each_entry_safe(goal, next, &(quota)->goals, list)
84191f21216SSeongJae Park
84298def236SSeongJae Park #define damos_for_each_filter(f, scheme) \
84398def236SSeongJae Park list_for_each_entry(f, &(scheme)->filters, list)
84498def236SSeongJae Park
84598def236SSeongJae Park #define damos_for_each_filter_safe(f, next, scheme) \
84698def236SSeongJae Park list_for_each_entry_safe(f, next, &(scheme)->filters, list)
84798def236SSeongJae Park
848ab82e579SSeongJae Park #define damos_for_each_ops_filter(f, scheme) \
849ab82e579SSeongJae Park list_for_each_entry(f, &(scheme)->ops_filters, list)
850ab82e579SSeongJae Park
851ab82e579SSeongJae Park #define damos_for_each_ops_filter_safe(f, next, scheme) \
852ab82e579SSeongJae Park list_for_each_entry_safe(f, next, &(scheme)->ops_filters, list)
853ab82e579SSeongJae Park
8542224d848SSeongJae Park #ifdef CONFIG_DAMON
8552224d848SSeongJae Park
856f23b8eeeSSeongJae Park struct damon_region *damon_new_region(unsigned long start, unsigned long end);
8572cd4b8e1SGuoqing Jiang
8582cd4b8e1SGuoqing Jiang /*
8592cd4b8e1SGuoqing Jiang * Add a region between two other regions
8602cd4b8e1SGuoqing Jiang */
damon_insert_region(struct damon_region * r,struct damon_region * prev,struct damon_region * next,struct damon_target * t)8612cd4b8e1SGuoqing Jiang static inline void damon_insert_region(struct damon_region *r,
862b9a6ac4eSSeongJae Park struct damon_region *prev, struct damon_region *next,
8632cd4b8e1SGuoqing Jiang struct damon_target *t)
8642cd4b8e1SGuoqing Jiang {
8652cd4b8e1SGuoqing Jiang __list_add(&r->list, &prev->list, &next->list);
8662cd4b8e1SGuoqing Jiang t->nr_regions++;
8672cd4b8e1SGuoqing Jiang }
8682cd4b8e1SGuoqing Jiang
869f23b8eeeSSeongJae Park void damon_add_region(struct damon_region *r, struct damon_target *t);
870b9a6ac4eSSeongJae Park void damon_destroy_region(struct damon_region *r, struct damon_target *t);
871d0723bc0SSeongJae Park int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
872d0723bc0SSeongJae Park unsigned int nr_ranges);
873ace30fb2SSeongJae Park void damon_update_region_access_rate(struct damon_region *r, bool accessed,
874ace30fb2SSeongJae Park struct damon_attrs *attrs);
875f23b8eeeSSeongJae Park
87698def236SSeongJae Park struct damos_filter *damos_new_filter(enum damos_filter_type type,
877e2fbfedaSSeongJae Park bool matching, bool allow);
87898def236SSeongJae Park void damos_add_filter(struct damos *s, struct damos_filter *f);
879f7f0d88bSSeongJae Park bool damos_filter_for_ops(enum damos_filter_type type);
88098def236SSeongJae Park void damos_destroy_filter(struct damos_filter *f);
88198def236SSeongJae Park
88291f21216SSeongJae Park struct damos_quota_goal *damos_new_quota_goal(
883bcce9bc1SSeongJae Park enum damos_quota_goal_metric metric,
884bcce9bc1SSeongJae Park unsigned long target_value);
88591f21216SSeongJae Park void damos_add_quota_goal(struct damos_quota *q, struct damos_quota_goal *g);
88691f21216SSeongJae Park void damos_destroy_quota_goal(struct damos_quota_goal *goal);
88791f21216SSeongJae Park
888f5a79d7cSYajun Deng struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
88942f994b7SSeongJae Park enum damos_action action,
89042f994b7SSeongJae Park unsigned long apply_interval_us,
89142f994b7SSeongJae Park struct damos_quota *quota,
892e36287c6SHyeongtak Ji struct damos_watermarks *wmarks,
893e36287c6SHyeongtak Ji int target_nid);
8941f366e42SSeongJae Park void damon_add_scheme(struct damon_ctx *ctx, struct damos *s);
8951f366e42SSeongJae Park void damon_destroy_scheme(struct damos *s);
8963ad1dce6SSeongJae Park int damos_commit_quota_goals(struct damos_quota *dst, struct damos_quota *src);
8971f366e42SSeongJae Park
8981971bd63SSeongJae Park struct damon_target *damon_new_target(void);
899f23b8eeeSSeongJae Park void damon_add_target(struct damon_ctx *ctx, struct damon_target *t);
900b5ca3e83SXin Hao bool damon_targets_empty(struct damon_ctx *ctx);
901f23b8eeeSSeongJae Park void damon_free_target(struct damon_target *t);
902f23b8eeeSSeongJae Park void damon_destroy_target(struct damon_target *t);
903b9a6ac4eSSeongJae Park unsigned int damon_nr_regions(struct damon_target *t);
904f23b8eeeSSeongJae Park
9052224d848SSeongJae Park struct damon_ctx *damon_new_ctx(void);
9062224d848SSeongJae Park void damon_destroy_ctx(struct damon_ctx *ctx);
907bead3b00SSeongJae Park int damon_set_attrs(struct damon_ctx *ctx, struct damon_attrs *attrs);
908cc713520SKaixu Xia void damon_set_schemes(struct damon_ctx *ctx,
9091f366e42SSeongJae Park struct damos **schemes, ssize_t nr_schemes);
9109cb3d0b9SSeongJae Park int damon_commit_ctx(struct damon_ctx *old_ctx, struct damon_ctx *new_ctx);
9114bc05954SSeongJae Park int damon_nr_running_ctxs(void);
912152e5617SSeongJae Park bool damon_is_registered_ops(enum damon_ops_id id);
9139f7b053aSSeongJae Park int damon_register_ops(struct damon_operations *ops);
9149f7b053aSSeongJae Park int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id);
9152224d848SSeongJae Park
damon_target_has_pid(const struct damon_ctx * ctx)916c9e124e0SSeongJae Park static inline bool damon_target_has_pid(const struct damon_ctx *ctx)
917c9e124e0SSeongJae Park {
918c9e124e0SSeongJae Park return ctx->ops.id == DAMON_OPS_VADDR || ctx->ops.id == DAMON_OPS_FVADDR;
919c9e124e0SSeongJae Park }
920c9e124e0SSeongJae Park
damon_max_nr_accesses(const struct damon_attrs * attrs)92135f5d941SSeongJae Park static inline unsigned int damon_max_nr_accesses(const struct damon_attrs *attrs)
92235f5d941SSeongJae Park {
92335f5d941SSeongJae Park /* {aggr,sample}_interval are unsigned long, hence could overflow */
92435f5d941SSeongJae Park return min(attrs->aggr_interval / attrs->sample_interval,
92535f5d941SSeongJae Park (unsigned long)UINT_MAX);
92635f5d941SSeongJae Park }
92735f5d941SSeongJae Park
928c9e124e0SSeongJae Park
9298b9b0d33SSeongJae Park int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive);
9302224d848SSeongJae Park int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
9312224d848SSeongJae Park
93242b7491aSSeongJae Park int damon_call(struct damon_ctx *ctx, struct damon_call_control *control);
933bf0eaba0SSeongJae Park int damos_walk(struct damon_ctx *ctx, struct damos_walk_control *control);
93442b7491aSSeongJae Park
935233f0b31SKaixu Xia int damon_set_region_biggest_system_ram_default(struct damon_target *t,
936233f0b31SKaixu Xia unsigned long *start, unsigned long *end);
9370d83b2d8SXin Hao
9382224d848SSeongJae Park #endif /* CONFIG_DAMON */
9392224d848SSeongJae Park
9402224d848SSeongJae Park #endif /* _DAMON_H */
941