![]() |
|
|||
0001 /* SPDX-License-Identifier: GPL-2.0 */ 0002 /* 0003 * DAMON api 0004 * 0005 * Author: SeongJae Park <sjpark@amazon.de> 0006 */ 0007 0008 #ifndef _DAMON_H_ 0009 #define _DAMON_H_ 0010 0011 #include <linux/mutex.h> 0012 #include <linux/time64.h> 0013 #include <linux/types.h> 0014 #include <linux/random.h> 0015 0016 /* Minimal region size. Every damon_region is aligned by this. */ 0017 #define DAMON_MIN_REGION PAGE_SIZE 0018 /* Max priority score for DAMON-based operation schemes */ 0019 #define DAMOS_MAX_SCORE (99) 0020 0021 /* Get a random number in [l, r) */ 0022 static inline unsigned long damon_rand(unsigned long l, unsigned long r) 0023 { 0024 return l + prandom_u32_max(r - l); 0025 } 0026 0027 /** 0028 * struct damon_addr_range - Represents an address region of [@start, @end). 0029 * @start: Start address of the region (inclusive). 0030 * @end: End address of the region (exclusive). 0031 */ 0032 struct damon_addr_range { 0033 unsigned long start; 0034 unsigned long end; 0035 }; 0036 0037 /** 0038 * struct damon_region - Represents a monitoring target region. 0039 * @ar: The address range of the region. 0040 * @sampling_addr: Address of the sample for the next access check. 0041 * @nr_accesses: Access frequency of this region. 0042 * @list: List head for siblings. 0043 * @age: Age of this region. 0044 * 0045 * @age is initially zero, increased for each aggregation interval, and reset 0046 * to zero again if the access frequency is significantly changed. If two 0047 * regions are merged into a new region, both @nr_accesses and @age of the new 0048 * region are set as region size-weighted average of those of the two regions. 0049 */ 0050 struct damon_region { 0051 struct damon_addr_range ar; 0052 unsigned long sampling_addr; 0053 unsigned int nr_accesses; 0054 struct list_head list; 0055 0056 unsigned int age; 0057 /* private: Internal value for age calculation. */ 0058 unsigned int last_nr_accesses; 0059 }; 0060 0061 /** 0062 * struct damon_target - Represents a monitoring target. 0063 * @pid: The PID of the virtual address space to monitor. 0064 * @nr_regions: Number of monitoring target regions of this target. 0065 * @regions_list: Head of the monitoring target regions of this target. 0066 * @list: List head for siblings. 0067 * 0068 * Each monitoring context could have multiple targets. For example, a context 0069 * for virtual memory address spaces could have multiple target processes. The 0070 * @pid should be set for appropriate &struct damon_operations including the 0071 * virtual address spaces monitoring operations. 0072 */ 0073 struct damon_target { 0074 struct pid *pid; 0075 unsigned int nr_regions; 0076 struct list_head regions_list; 0077 struct list_head list; 0078 }; 0079 0080 /** 0081 * enum damos_action - Represents an action of a Data Access Monitoring-based 0082 * Operation Scheme. 0083 * 0084 * @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED. 0085 * @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD. 0086 * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT. 0087 * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE. 0088 * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE. 0089 * @DAMOS_LRU_PRIO: Prioritize the region on its LRU lists. 0090 * @DAMOS_LRU_DEPRIO: Deprioritize the region on its LRU lists. 0091 * @DAMOS_STAT: Do nothing but count the stat. 0092 * @NR_DAMOS_ACTIONS: Total number of DAMOS actions 0093 */ 0094 enum damos_action { 0095 DAMOS_WILLNEED, 0096 DAMOS_COLD, 0097 DAMOS_PAGEOUT, 0098 DAMOS_HUGEPAGE, 0099 DAMOS_NOHUGEPAGE, 0100 DAMOS_LRU_PRIO, 0101 DAMOS_LRU_DEPRIO, 0102 DAMOS_STAT, /* Do nothing but only record the stat */ 0103 NR_DAMOS_ACTIONS, 0104 }; 0105 0106 /** 0107 * struct damos_quota - Controls the aggressiveness of the given scheme. 0108 * @ms: Maximum milliseconds that the scheme can use. 0109 * @sz: Maximum bytes of memory that the action can be applied. 0110 * @reset_interval: Charge reset interval in milliseconds. 0111 * 0112 * @weight_sz: Weight of the region's size for prioritization. 0113 * @weight_nr_accesses: Weight of the region's nr_accesses for prioritization. 0114 * @weight_age: Weight of the region's age for prioritization. 0115 * 0116 * To avoid consuming too much CPU time or IO resources for applying the 0117 * &struct damos->action to large memory, DAMON allows users to set time and/or 0118 * size quotas. The quotas can be set by writing non-zero values to &ms and 0119 * &sz, respectively. If the time quota is set, DAMON tries to use only up to 0120 * &ms milliseconds within &reset_interval for applying the action. If the 0121 * size quota is set, DAMON tries to apply the action only up to &sz bytes 0122 * within &reset_interval. 0123 * 0124 * Internally, the time quota is transformed to a size quota using estimated 0125 * throughput of the scheme's action. DAMON then compares it against &sz and 0126 * uses smaller one as the effective quota. 0127 * 0128 * For selecting regions within the quota, DAMON prioritizes current scheme's 0129 * target memory regions using the &struct damon_operations->get_scheme_score. 0130 * You could customize the prioritization logic by setting &weight_sz, 0131 * &weight_nr_accesses, and &weight_age, because monitoring operations are 0132 * encouraged to respect those. 0133 */ 0134 struct damos_quota { 0135 unsigned long ms; 0136 unsigned long sz; 0137 unsigned long reset_interval; 0138 0139 unsigned int weight_sz; 0140 unsigned int weight_nr_accesses; 0141 unsigned int weight_age; 0142 0143 /* private: */ 0144 /* For throughput estimation */ 0145 unsigned long total_charged_sz; 0146 unsigned long total_charged_ns; 0147 0148 unsigned long esz; /* Effective size quota in bytes */ 0149 0150 /* For charging the quota */ 0151 unsigned long charged_sz; 0152 unsigned long charged_from; 0153 struct damon_target *charge_target_from; 0154 unsigned long charge_addr_from; 0155 0156 /* For prioritization */ 0157 unsigned long histogram[DAMOS_MAX_SCORE + 1]; 0158 unsigned int min_score; 0159 }; 0160 0161 /** 0162 * enum damos_wmark_metric - Represents the watermark metric. 0163 * 0164 * @DAMOS_WMARK_NONE: Ignore the watermarks of the given scheme. 0165 * @DAMOS_WMARK_FREE_MEM_RATE: Free memory rate of the system in [0,1000]. 0166 * @NR_DAMOS_WMARK_METRICS: Total number of DAMOS watermark metrics 0167 */ 0168 enum damos_wmark_metric { 0169 DAMOS_WMARK_NONE, 0170 DAMOS_WMARK_FREE_MEM_RATE, 0171 NR_DAMOS_WMARK_METRICS, 0172 }; 0173 0174 /** 0175 * struct damos_watermarks - Controls when a given scheme should be activated. 0176 * @metric: Metric for the watermarks. 0177 * @interval: Watermarks check time interval in microseconds. 0178 * @high: High watermark. 0179 * @mid: Middle watermark. 0180 * @low: Low watermark. 0181 * 0182 * If &metric is &DAMOS_WMARK_NONE, the scheme is always active. Being active 0183 * means DAMON does monitoring and applying the action of the scheme to 0184 * appropriate memory regions. Else, DAMON checks &metric of the system for at 0185 * least every &interval microseconds and works as below. 0186 * 0187 * If &metric is higher than &high, the scheme is inactivated. If &metric is 0188 * between &mid and &low, the scheme is activated. If &metric is lower than 0189 * &low, the scheme is inactivated. 0190 */ 0191 struct damos_watermarks { 0192 enum damos_wmark_metric metric; 0193 unsigned long interval; 0194 unsigned long high; 0195 unsigned long mid; 0196 unsigned long low; 0197 0198 /* private: */ 0199 bool activated; 0200 }; 0201 0202 /** 0203 * struct damos_stat - Statistics on a given scheme. 0204 * @nr_tried: Total number of regions that the scheme is tried to be applied. 0205 * @sz_tried: Total size of regions that the scheme is tried to be applied. 0206 * @nr_applied: Total number of regions that the scheme is applied. 0207 * @sz_applied: Total size of regions that the scheme is applied. 0208 * @qt_exceeds: Total number of times the quota of the scheme has exceeded. 0209 */ 0210 struct damos_stat { 0211 unsigned long nr_tried; 0212 unsigned long sz_tried; 0213 unsigned long nr_applied; 0214 unsigned long sz_applied; 0215 unsigned long qt_exceeds; 0216 }; 0217 0218 /** 0219 * struct damos - Represents a Data Access Monitoring-based Operation Scheme. 0220 * @min_sz_region: Minimum size of target regions. 0221 * @max_sz_region: Maximum size of target regions. 0222 * @min_nr_accesses: Minimum ``->nr_accesses`` of target regions. 0223 * @max_nr_accesses: Maximum ``->nr_accesses`` of target regions. 0224 * @min_age_region: Minimum age of target regions. 0225 * @max_age_region: Maximum age of target regions. 0226 * @action: &damo_action to be applied to the target regions. 0227 * @quota: Control the aggressiveness of this scheme. 0228 * @wmarks: Watermarks for automated (in)activation of this scheme. 0229 * @stat: Statistics of this scheme. 0230 * @list: List head for siblings. 0231 * 0232 * For each aggregation interval, DAMON finds regions which fit in the 0233 * condition (&min_sz_region, &max_sz_region, &min_nr_accesses, 0234 * &max_nr_accesses, &min_age_region, &max_age_region) and applies &action to 0235 * those. To avoid consuming too much CPU time or IO resources for the 0236 * &action, "a is used. 0237 * 0238 * To do the work only when needed, schemes can be activated for specific 0239 * system situations using &wmarks. If all schemes that registered to the 0240 * monitoring context are inactive, DAMON stops monitoring either, and just 0241 * repeatedly checks the watermarks. 0242 * 0243 * If all schemes that registered to a &struct damon_ctx are inactive, DAMON 0244 * stops monitoring and just repeatedly checks the watermarks. 0245 * 0246 * After applying the &action to each region, &stat_count and &stat_sz is 0247 * updated to reflect the number of regions and total size of regions that the 0248 * &action is applied. 0249 */ 0250 struct damos { 0251 unsigned long min_sz_region; 0252 unsigned long max_sz_region; 0253 unsigned int min_nr_accesses; 0254 unsigned int max_nr_accesses; 0255 unsigned int min_age_region; 0256 unsigned int max_age_region; 0257 enum damos_action action; 0258 struct damos_quota quota; 0259 struct damos_watermarks wmarks; 0260 struct damos_stat stat; 0261 struct list_head list; 0262 }; 0263 0264 /** 0265 * enum damon_ops_id - Identifier for each monitoring operations implementation 0266 * 0267 * @DAMON_OPS_VADDR: Monitoring operations for virtual address spaces 0268 * @DAMON_OPS_FVADDR: Monitoring operations for only fixed ranges of virtual 0269 * address spaces 0270 * @DAMON_OPS_PADDR: Monitoring operations for the physical address space 0271 * @NR_DAMON_OPS: Number of monitoring operations implementations 0272 */ 0273 enum damon_ops_id { 0274 DAMON_OPS_VADDR, 0275 DAMON_OPS_FVADDR, 0276 DAMON_OPS_PADDR, 0277 NR_DAMON_OPS, 0278 }; 0279 0280 struct damon_ctx; 0281 0282 /** 0283 * struct damon_operations - Monitoring operations for given use cases. 0284 * 0285 * @id: Identifier of this operations set. 0286 * @init: Initialize operations-related data structures. 0287 * @update: Update operations-related data structures. 0288 * @prepare_access_checks: Prepare next access check of target regions. 0289 * @check_accesses: Check the accesses to target regions. 0290 * @reset_aggregated: Reset aggregated accesses monitoring results. 0291 * @get_scheme_score: Get the score of a region for a scheme. 0292 * @apply_scheme: Apply a DAMON-based operation scheme. 0293 * @target_valid: Determine if the target is valid. 0294 * @cleanup: Clean up the context. 0295 * 0296 * DAMON can be extended for various address spaces and usages. For this, 0297 * users should register the low level operations for their target address 0298 * space and usecase via the &damon_ctx.ops. Then, the monitoring thread 0299 * (&damon_ctx.kdamond) calls @init and @prepare_access_checks before starting 0300 * the monitoring, @update after each &damon_ctx.ops_update_interval, and 0301 * @check_accesses, @target_valid and @prepare_access_checks after each 0302 * &damon_ctx.sample_interval. Finally, @reset_aggregated is called after each 0303 * &damon_ctx.aggr_interval. 0304 * 0305 * Each &struct damon_operations instance having valid @id can be registered 0306 * via damon_register_ops() and selected by damon_select_ops() later. 0307 * @init should initialize operations-related data structures. For example, 0308 * this could be used to construct proper monitoring target regions and link 0309 * those to @damon_ctx.adaptive_targets. 0310 * @update should update the operations-related data structures. For example, 0311 * this could be used to update monitoring target regions for current status. 0312 * @prepare_access_checks should manipulate the monitoring regions to be 0313 * prepared for the next access check. 0314 * @check_accesses should check the accesses to each region that made after the 0315 * last preparation and update the number of observed accesses of each region. 0316 * It should also return max number of observed accesses that made as a result 0317 * of its update. The value will be used for regions adjustment threshold. 0318 * @reset_aggregated should reset the access monitoring results that aggregated 0319 * by @check_accesses. 0320 * @get_scheme_score should return the priority score of a region for a scheme 0321 * as an integer in [0, &DAMOS_MAX_SCORE]. 0322 * @apply_scheme is called from @kdamond when a region for user provided 0323 * DAMON-based operation scheme is found. It should apply the scheme's action 0324 * to the region and return bytes of the region that the action is successfully 0325 * applied. 0326 * @target_valid should check whether the target is still valid for the 0327 * monitoring. 0328 * @cleanup is called from @kdamond just before its termination. 0329 */ 0330 struct damon_operations { 0331 enum damon_ops_id id; 0332 void (*init)(struct damon_ctx *context); 0333 void (*update)(struct damon_ctx *context); 0334 void (*prepare_access_checks)(struct damon_ctx *context); 0335 unsigned int (*check_accesses)(struct damon_ctx *context); 0336 void (*reset_aggregated)(struct damon_ctx *context); 0337 int (*get_scheme_score)(struct damon_ctx *context, 0338 struct damon_target *t, struct damon_region *r, 0339 struct damos *scheme); 0340 unsigned long (*apply_scheme)(struct damon_ctx *context, 0341 struct damon_target *t, struct damon_region *r, 0342 struct damos *scheme); 0343 bool (*target_valid)(void *target); 0344 void (*cleanup)(struct damon_ctx *context); 0345 }; 0346 0347 /** 0348 * struct damon_callback - Monitoring events notification callbacks. 0349 * 0350 * @before_start: Called before starting the monitoring. 0351 * @after_wmarks_check: Called after each schemes' watermarks check. 0352 * @after_sampling: Called after each sampling. 0353 * @after_aggregation: Called after each aggregation. 0354 * @before_terminate: Called before terminating the monitoring. 0355 * @private: User private data. 0356 * 0357 * The monitoring thread (&damon_ctx.kdamond) calls @before_start and 0358 * @before_terminate just before starting and finishing the monitoring, 0359 * respectively. Therefore, those are good places for installing and cleaning 0360 * @private. 0361 * 0362 * The monitoring thread calls @after_wmarks_check after each DAMON-based 0363 * operation schemes' watermarks check. If users need to make changes to the 0364 * attributes of the monitoring context while it's deactivated due to the 0365 * watermarks, this is the good place to do. 0366 * 0367 * The monitoring thread calls @after_sampling and @after_aggregation for each 0368 * of the sampling intervals and aggregation intervals, respectively. 0369 * Therefore, users can safely access the monitoring results without additional 0370 * protection. For the reason, users are recommended to use these callback for 0371 * the accesses to the results. 0372 * 0373 * If any callback returns non-zero, monitoring stops. 0374 */ 0375 struct damon_callback { 0376 void *private; 0377 0378 int (*before_start)(struct damon_ctx *context); 0379 int (*after_wmarks_check)(struct damon_ctx *context); 0380 int (*after_sampling)(struct damon_ctx *context); 0381 int (*after_aggregation)(struct damon_ctx *context); 0382 void (*before_terminate)(struct damon_ctx *context); 0383 }; 0384 0385 /** 0386 * struct damon_ctx - Represents a context for each monitoring. This is the 0387 * main interface that allows users to set the attributes and get the results 0388 * of the monitoring. 0389 * 0390 * @sample_interval: The time between access samplings. 0391 * @aggr_interval: The time between monitor results aggregations. 0392 * @ops_update_interval: The time between monitoring operations updates. 0393 * 0394 * For each @sample_interval, DAMON checks whether each region is accessed or 0395 * not. It aggregates and keeps the access information (number of accesses to 0396 * each region) for @aggr_interval time. DAMON also checks whether the target 0397 * memory regions need update (e.g., by ``mmap()`` calls from the application, 0398 * in case of virtual memory monitoring) and applies the changes for each 0399 * @ops_update_interval. All time intervals are in micro-seconds. 0400 * Please refer to &struct damon_operations and &struct damon_callback for more 0401 * detail. 0402 * 0403 * @kdamond: Kernel thread who does the monitoring. 0404 * @kdamond_lock: Mutex for the synchronizations with @kdamond. 0405 * 0406 * For each monitoring context, one kernel thread for the monitoring is 0407 * created. The pointer to the thread is stored in @kdamond. 0408 * 0409 * Once started, the monitoring thread runs until explicitly required to be 0410 * terminated or every monitoring target is invalid. The validity of the 0411 * targets is checked via the &damon_operations.target_valid of @ops. The 0412 * termination can also be explicitly requested by calling damon_stop(). 0413 * The thread sets @kdamond to NULL when it terminates. Therefore, users can 0414 * know whether the monitoring is ongoing or terminated by reading @kdamond. 0415 * Reads and writes to @kdamond from outside of the monitoring thread must 0416 * be protected by @kdamond_lock. 0417 * 0418 * Note that the monitoring thread protects only @kdamond via @kdamond_lock. 0419 * Accesses to other fields must be protected by themselves. 0420 * 0421 * @ops: Set of monitoring operations for given use cases. 0422 * @callback: Set of callbacks for monitoring events notifications. 0423 * 0424 * @min_nr_regions: The minimum number of adaptive monitoring regions. 0425 * @max_nr_regions: The maximum number of adaptive monitoring regions. 0426 * @adaptive_targets: Head of monitoring targets (&damon_target) list. 0427 * @schemes: Head of schemes (&damos) list. 0428 */ 0429 struct damon_ctx { 0430 unsigned long sample_interval; 0431 unsigned long aggr_interval; 0432 unsigned long ops_update_interval; 0433 0434 /* private: internal use only */ 0435 struct timespec64 last_aggregation; 0436 struct timespec64 last_ops_update; 0437 0438 /* public: */ 0439 struct task_struct *kdamond; 0440 struct mutex kdamond_lock; 0441 0442 struct damon_operations ops; 0443 struct damon_callback callback; 0444 0445 unsigned long min_nr_regions; 0446 unsigned long max_nr_regions; 0447 struct list_head adaptive_targets; 0448 struct list_head schemes; 0449 }; 0450 0451 static inline struct damon_region *damon_next_region(struct damon_region *r) 0452 { 0453 return container_of(r->list.next, struct damon_region, list); 0454 } 0455 0456 static inline struct damon_region *damon_prev_region(struct damon_region *r) 0457 { 0458 return container_of(r->list.prev, struct damon_region, list); 0459 } 0460 0461 static inline struct damon_region *damon_last_region(struct damon_target *t) 0462 { 0463 return list_last_entry(&t->regions_list, struct damon_region, list); 0464 } 0465 0466 #define damon_for_each_region(r, t) \ 0467 list_for_each_entry(r, &t->regions_list, list) 0468 0469 #define damon_for_each_region_safe(r, next, t) \ 0470 list_for_each_entry_safe(r, next, &t->regions_list, list) 0471 0472 #define damon_for_each_target(t, ctx) \ 0473 list_for_each_entry(t, &(ctx)->adaptive_targets, list) 0474 0475 #define damon_for_each_target_safe(t, next, ctx) \ 0476 list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list) 0477 0478 #define damon_for_each_scheme(s, ctx) \ 0479 list_for_each_entry(s, &(ctx)->schemes, list) 0480 0481 #define damon_for_each_scheme_safe(s, next, ctx) \ 0482 list_for_each_entry_safe(s, next, &(ctx)->schemes, list) 0483 0484 #ifdef CONFIG_DAMON 0485 0486 struct damon_region *damon_new_region(unsigned long start, unsigned long end); 0487 0488 /* 0489 * Add a region between two other regions 0490 */ 0491 static inline void damon_insert_region(struct damon_region *r, 0492 struct damon_region *prev, struct damon_region *next, 0493 struct damon_target *t) 0494 { 0495 __list_add(&r->list, &prev->list, &next->list); 0496 t->nr_regions++; 0497 } 0498 0499 void damon_add_region(struct damon_region *r, struct damon_target *t); 0500 void damon_destroy_region(struct damon_region *r, struct damon_target *t); 0501 int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges, 0502 unsigned int nr_ranges); 0503 0504 struct damos *damon_new_scheme( 0505 unsigned long min_sz_region, unsigned long max_sz_region, 0506 unsigned int min_nr_accesses, unsigned int max_nr_accesses, 0507 unsigned int min_age_region, unsigned int max_age_region, 0508 enum damos_action action, struct damos_quota *quota, 0509 struct damos_watermarks *wmarks); 0510 void damon_add_scheme(struct damon_ctx *ctx, struct damos *s); 0511 void damon_destroy_scheme(struct damos *s); 0512 0513 struct damon_target *damon_new_target(void); 0514 void damon_add_target(struct damon_ctx *ctx, struct damon_target *t); 0515 bool damon_targets_empty(struct damon_ctx *ctx); 0516 void damon_free_target(struct damon_target *t); 0517 void damon_destroy_target(struct damon_target *t); 0518 unsigned int damon_nr_regions(struct damon_target *t); 0519 0520 struct damon_ctx *damon_new_ctx(void); 0521 void damon_destroy_ctx(struct damon_ctx *ctx); 0522 int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, 0523 unsigned long aggr_int, unsigned long ops_upd_int, 0524 unsigned long min_nr_reg, unsigned long max_nr_reg); 0525 int damon_set_schemes(struct damon_ctx *ctx, 0526 struct damos **schemes, ssize_t nr_schemes); 0527 int damon_nr_running_ctxs(void); 0528 bool damon_is_registered_ops(enum damon_ops_id id); 0529 int damon_register_ops(struct damon_operations *ops); 0530 int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id); 0531 0532 static inline bool damon_target_has_pid(const struct damon_ctx *ctx) 0533 { 0534 return ctx->ops.id == DAMON_OPS_VADDR || ctx->ops.id == DAMON_OPS_FVADDR; 0535 } 0536 0537 0538 int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive); 0539 int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); 0540 0541 #endif /* CONFIG_DAMON */ 0542 0543 #endif /* _DAMON_H */
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |