diff options
Diffstat (limited to 'include/linux/damon.h')
| -rw-r--r-- | include/linux/damon.h | 173 |
1 files changed, 94 insertions, 79 deletions
diff --git a/include/linux/damon.h b/include/linux/damon.h index cfbbf8ba28f6..0c8b7ddef9ab 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -45,13 +45,11 @@ struct damon_size_range { * @ar: The address range of the region. * @sampling_addr: Address of the sample for the next access check. * @nr_accesses: Access frequency of this region. - * @nr_accesses_bp: @nr_accesses in basis point (0.01%) that updated for - * each sampling interval. * @probe_hits: Number of probe-positive region samples. - * @list: List head for siblings. * @age: Age of this region. * - * For any use case, @ar should be non-zero positive size. + * For any use case, @ar should be non-zero positive size. damon_set_regions() + * does the validation. * * @nr_accesses is reset to zero for every &damon_attrs->aggr_interval and be * increased for every &damon_attrs->sample_interval if an access to the region @@ -59,13 +57,6 @@ struct damon_size_range { * not be done with direct access but with the helper function, * damon_update_region_access_rate(). * - * @nr_accesses_bp is another representation of @nr_accesses in basis point - * (1 in 10,000) that updated for every &damon_attrs->sample_interval in a - * manner similar to moving sum. By the algorithm, this value becomes - * @nr_accesses * 10000 for every &struct damon_attrs->aggr_interval. This can - * be used when the aggregation interval is too huge and therefore cannot wait - * for it before getting the access monitoring results. - * * @age is initially zero, increased for each aggregation interval, and reset * to zero again if the access frequency is significantly changed. If two * regions are merged into a new region, both @nr_accesses and @age of the new @@ -75,21 +66,19 @@ struct damon_region { struct damon_addr_range ar; unsigned long sampling_addr; unsigned int nr_accesses; - unsigned int nr_accesses_bp; unsigned char probe_hits[DAMON_MAX_PROBES]; - struct list_head list; - unsigned int age; -/* private: Internal value for age calculation. */ +/* private: internal use only. */ + /* List head for siblings. */ + struct list_head list; + /* for age calculation. */ unsigned int last_nr_accesses; + unsigned char last_probe_hits[DAMON_MAX_PROBES]; }; /** * struct damon_target - Represents a monitoring target. * @pid: The PID of the virtual address space to monitor. - * @nr_regions: Number of monitoring target regions of this target. - * @regions_list: Head of the monitoring target regions of this target. - * @list: List head for siblings. * @obsolete: Whether the commit destination target is obsolete. * * Each monitoring context could have multiple targets. For example, a context @@ -103,10 +92,14 @@ struct damon_region { */ struct damon_target { struct pid *pid; + bool obsolete; +/* private: */ + /* Number of monitoring target regions of this target. */ unsigned int nr_regions; + /* Head of the monitoring target regions of this target. */ struct list_head regions_list; + /* List head for siblings. */ struct list_head list; - bool obsolete; }; /** @@ -182,10 +175,8 @@ enum damos_quota_goal_metric { * @metric: Metric to be used for representing the goal. * @target_value: Target value of @metric to achieve with the tuning. * @current_value: Current value of @metric. - * @last_psi_total: Last measured total PSI * @nid: Node id. * @memcg_id: Memcg id. - * @list: List head for siblings. * * Data structure for getting the current score of the quota tuning goal. The * score is calculated by how close @current_value and @target_value are. Then @@ -208,12 +199,17 @@ struct damos_quota_goal { unsigned long current_value; /* metric-dependent fields */ union { - u64 last_psi_total; struct { int nid; u64 memcg_id; }; +/* private: */ + /* Last measured total PSI */ + u64 last_psi_total; + }; +/* private: */ + /* List head for siblings. */ struct list_head list; }; @@ -232,7 +228,6 @@ enum damos_quota_goal_tuner { * @reset_interval: Charge reset interval in milliseconds. * @ms: Maximum milliseconds that the scheme can use. * @sz: Maximum bytes of memory that the action can be applied. - * @goals: Head of quota tuning goals (&damos_quota_goal) list. * @goal_tuner: Goal-based @esz tuning algorithm to use. * @esz: Effective size quota in bytes. * @fail_charge_num: Failed regions charge rate numerator. @@ -259,7 +254,7 @@ enum damos_quota_goal_tuner { * the scheme's action. DAMON then compares it against &sz and uses smaller * one as the effective quota. * - * If @goals is not empty, DAMON calculates yet another size quota based on the + * If goals is not empty, DAMON calculates yet another size quota based on the * goals using its internal feedback loop algorithm, for every @reset_interval. * Then, if the new size quota is smaller than the effective quota, it uses the * new size quota as the effective quota. @@ -280,7 +275,7 @@ struct damos_quota { unsigned long reset_interval; unsigned long ms; unsigned long sz; - struct list_head goals; + enum damos_quota_goal_tuner goal_tuner; unsigned long esz; @@ -292,6 +287,8 @@ struct damos_quota { unsigned int weight_age; /* private: */ + /* Head of quota tuning goals (&damos_quota_goal) list. */ + struct list_head goals; /* For throughput estimation */ unsigned long total_charged_sz; unsigned long total_charged_ns; @@ -401,16 +398,15 @@ struct damos_stat { * @DAMOS_FILTER_TYPE_TARGET: Data Access Monitoring target. * @NR_DAMOS_FILTER_TYPES: Number of filter types. * - * The anon pages type and memcg type filters are handled by underlying - * &struct damon_operations as a part of scheme action trying, and therefore - * accounted as 'tried'. In contrast, other types are handled by core layer - * before trying of the action and therefore not accounted as 'tried'. + * All types except &DAMOS_FILTER_TYPE_ADDR and &DAMOS_FILTER_TYPE_TARGET + * are handled by the underlying &struct damon_operations as a part of scheme + * action trying, and therefore accounted as 'tried'. In contrast, + * &DAMOS_FILTER_TYPE_ADDR and &DAMOS_FILTER_TYPE_TARGET filters are handled + * by the core layer before trying of the action, and therefore not accounted + * as 'tried'. * - * The support of the filters that handled by &struct damon_operations depend - * on the running &struct damon_operations. - * &enum DAMON_OPS_PADDR supports both anon pages type and memcg type filters, - * while &enum DAMON_OPS_VADDR and &enum DAMON_OPS_FVADDR don't support any of - * the two types. + * Support for the operations-handled filters depends on the running + * &struct damon_operations. */ enum damos_filter_type { DAMOS_FILTER_TYPE_ANON, @@ -435,7 +431,6 @@ enum damos_filter_type { * &damon_ctx->adaptive_targets if @type is * DAMOS_FILTER_TYPE_TARGET. * @sz_range: Size range if @type is DAMOS_FILTER_TYPE_HUGEPAGE_SIZE. - * @list: List head for siblings. * * Before applying the &damos->action to a memory region, DAMOS checks if each * byte of the region matches to this given condition and avoid applying the @@ -453,6 +448,8 @@ struct damos_filter { int target_idx; struct damon_size_range sz_range; }; +/* private: */ + /* List head for siblings. */ struct list_head list; }; @@ -524,12 +521,8 @@ struct damos_migrate_dests { * @wmarks: Watermarks for automated (in)activation of this scheme. * @migrate_dests: Destination nodes if @action is "migrate_{hot,cold}". * @target_nid: Destination node if @action is "migrate_{hot,cold}". - * @core_filters: Additional set of &struct damos_filter for &action. - * @ops_filters: ops layer handling &struct damos_filter objects list. - * @last_applied: Last @action applied ops-managing entity. * @stat: Statistics of this scheme. * @max_nr_snapshots: Upper limit of nr_snapshots stat. - * @list: List head for siblings. * * For each @apply_interval_us, DAMON finds regions which fit in the * &pattern and applies &action to those. To avoid consuming too much @@ -551,16 +544,7 @@ struct damos_migrate_dests { * * Before applying the &action to a memory region, &struct damon_operations * implementation could check pages of the region and skip &action to respect - * &core_filters - * - * The minimum entity that @action can be applied depends on the underlying - * &struct damon_operations. Since it may not be aligned with the core layer - * abstract, namely &struct damon_region, &struct damon_operations could apply - * @action to same entity multiple times. Large folios that underlying on - * multiple &struct damon region objects could be such examples. The &struct - * damon_operations can use @last_applied to avoid that. DAMOS core logic - * unsets @last_applied when each regions walking for applying the scheme is - * finished. + * &struct damos_filter. * * After applying the &action to each region, &stat is updated. * @@ -571,6 +555,16 @@ struct damos { struct damos_access_pattern pattern; enum damos_action action; unsigned long apply_interval_us; + struct damos_quota quota; + struct damos_watermarks wmarks; + union { + struct { + int target_nid; + struct damos_migrate_dests migrate_dests; + }; + }; + struct damos_stat stat; + unsigned long max_nr_snapshots; /* private: internal use only */ /* * number of sample intervals that should be passed before applying @@ -587,20 +581,25 @@ struct damos { /* whether to reject core/ops filters umatched regions */ bool core_filters_default_reject; bool ops_filters_default_reject; -/* public: */ - struct damos_quota quota; - struct damos_watermarks wmarks; - union { - struct { - int target_nid; - struct damos_migrate_dests migrate_dests; - }; - }; + /* Additional set of &struct damos_filter for &action. */ struct list_head core_filters; + /* ops layer handling &struct damos_filter objects list. */ struct list_head ops_filters; + /* + * Last @action applied ops-managing entity. + * + * The minimum entity that @action can be applied depends on the + * underlying &struct damon_operations. Since it may not be aligned + * with the core layer abstract, namely &struct damon_region, &struct + * damon_operations could apply @action to same entity multiple times. + * Large folios that underlying on multiple &struct damon region + * objects could be such examples. The &struct damon_operations can + * use @last_applied to avoid that. DAMOS core logic unsets + * @last_applied when each regions walking for applying the scheme is + * finished. + */ void *last_applied; - struct damos_stat stat; - unsigned long max_nr_snapshots; + /* List head for siblings. */ struct list_head list; }; @@ -656,7 +655,10 @@ enum damon_ops_id { * It should also return max number of observed accesses that made as a result * of its update. The value will be used for regions adjustment threshold. * @apply_probes should apply the data attribute probes to each region and - * accordingly update the probe hits counter of the region. + * accordingly update the probe hits counter of the region. It should also + * set &damon_region->sampling_addr of each region if ``set_samples`` is true. + * It should also return maximum probe hits weighted sum of regions if + * ``return_max_wsum`` is true. * @get_scheme_score should return the priority score of a region for a scheme * as an integer in [0, &DAMOS_MAX_SCORE]. * @apply_scheme is called from @kdamond when a region for user provided @@ -674,7 +676,8 @@ struct damon_operations { void (*update)(struct damon_ctx *context); void (*prepare_access_checks)(struct damon_ctx *context); unsigned int (*check_accesses)(struct damon_ctx *context); - void (*apply_probes)(struct damon_ctx *context); + unsigned int (*apply_probes)(struct damon_ctx *context, + bool set_samples, bool return_max_wsum); int (*get_scheme_score)(struct damon_ctx *context, struct damon_region *r, struct damos *scheme); unsigned long (*apply_scheme)(struct damon_ctx *context, @@ -754,7 +757,6 @@ enum damon_filter_type { * @matching: Whether this filter is for the type-matching ones. * @allow: Whether the @type-@matching ones should pass this filter. * @memcg_id: Memcg id of the question if @type is DAMON_FILTER_MEMCG. - * @list: Siblings list. */ struct damon_filter { enum damon_filter_type type; @@ -763,17 +765,22 @@ struct damon_filter { union { u64 memcg_id; }; +/* private: */ + /* Siblings list. */ struct list_head list; }; /** * struct damon_probe - Data region attribute probe. * - * @filters: Filters for assessing if a given region is for this probe. - * @list: Siblings list. + * @weight: Relative priority of the attribute for this probe. */ struct damon_probe { + unsigned int weight; +/* private: */ + /* Filters for assessing if a given region is for this probe. */ struct list_head filters; + /* Siblings list. */ struct list_head list; }; @@ -840,14 +847,9 @@ struct damon_attrs { * thread other than the kdamond should be made using safe DAMON APIs, * including damon_call() and damos_walk(). * - * @ops: Set of monitoring operations for given use cases. - * @probes: Head of probes (&damon_probe) list. * @addr_unit: Scale factor for core to ops address conversion. * @min_region_sz: Minimum region size. * @pause: Pause kdamond main loop. - * @adaptive_targets: Head of monitoring targets (&damon_target) list. - * @schemes: Head of schemes (&damos) list. - * @rnd_state: Per-ctx PRNG state for damon_rand(). */ struct damon_ctx { struct damon_attrs attrs; @@ -896,15 +898,21 @@ struct damon_ctx { struct mutex kdamond_lock; /* public: */ - struct damon_operations ops; - struct list_head probes; unsigned long addr_unit; unsigned long min_region_sz; bool pause; +/* private: */ + /* Set of monitoring operations for given use cases. */ + struct damon_operations ops; + /* Head of monitoring targets (&damon_target) list. */ struct list_head adaptive_targets; + /* Head of probes (&damon_probe) list. */ + struct list_head probes; + /* Head of schemes (&damos) list. */ struct list_head schemes; + /* @rnd_state: Per-ctx PRNG state for damon_rand(). */ struct rnd_state rnd_state; }; @@ -1011,11 +1019,16 @@ struct damon_probe *damon_new_probe(void); 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); +unsigned int damon_probe_hits_wsum(struct damon_region *r, bool last, + 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); -void damon_update_region_access_rate(struct damon_region *r, bool accessed, - struct damon_attrs *attrs); +void damon_update_region_access_rate(struct damon_region *r, bool accessed); struct damos_filter *damos_new_filter(enum damos_filter_type type, bool matching, bool allow); @@ -1062,21 +1075,23 @@ static inline bool damon_target_has_pid(const struct damon_ctx *ctx) return ctx->ops.id == DAMON_OPS_VADDR || ctx->ops.id == DAMON_OPS_FVADDR; } -static inline unsigned int damon_max_nr_accesses(const struct damon_attrs *attrs) +/* Returns number of samples per aggregation interval */ +static inline unsigned int damon_nr_samples_per_aggr( + const struct damon_attrs *attrs) { unsigned long sample_interval; - unsigned long max_nr_accesses; + unsigned long nr_samples; sample_interval = attrs->sample_interval ? : 1; - max_nr_accesses = min(attrs->aggr_interval / sample_interval, + nr_samples = min(attrs->aggr_interval / sample_interval, (unsigned long)UINT_MAX); - return max_nr_accesses ? : 1; + return nr_samples ? : 1; } bool damon_initialized(void); int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive); -int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); +void damon_stop(struct damon_ctx **ctxs, int nr_ctxs); bool damon_is_running(struct damon_ctx *ctx); int damon_kdamond_pid(struct damon_ctx *ctx); |
