Lines Matching +full:monitor +full:- +full:interval +full:- +full:ms

1 // SPDX-License-Identifier: GPL-2.0
3 * Data Access Monitor
45 * damon_is_registered_ops() - Check if a given damon_operations is registered.
63 * damon_register_ops() - Register a monitoring operations set to DAMON.
67 * damon_operations->id so that others can find and use them later.
75 if (ops->id >= NR_DAMON_OPS) in damon_register_ops()
76 return -EINVAL; in damon_register_ops()
79 if (__damon_is_registered_ops(ops->id)) { in damon_register_ops()
80 err = -EINVAL; in damon_register_ops()
83 damon_registered_ops[ops->id] = *ops; in damon_register_ops()
90 * damon_select_ops() - Select a monitoring operations to use with the context.
104 return -EINVAL; in damon_select_ops()
108 err = -EINVAL; in damon_select_ops()
110 ctx->ops = damon_registered_ops[id]; in damon_select_ops()
128 region->ar.start = start; in damon_new_region()
129 region->ar.end = end; in damon_new_region()
130 region->nr_accesses = 0; in damon_new_region()
131 INIT_LIST_HEAD(&region->list); in damon_new_region()
133 region->age = 0; in damon_new_region()
134 region->last_nr_accesses = 0; in damon_new_region()
141 list_add_tail(&r->list, &t->regions_list); in damon_add_region()
142 t->nr_regions++; in damon_add_region()
147 list_del(&r->list); in damon_del_region()
148 t->nr_regions--; in damon_del_region()
170 return !(r->ar.end <= re->start || re->end <= r->ar.start); in damon_intersect()
187 if (r->ar.end != next->ar.start) { in damon_fill_regions_holes()
188 newr = damon_new_region(r->ar.end, next->ar.start); in damon_fill_regions_holes()
190 return -ENOMEM; in damon_fill_regions_holes()
198 * damon_set_regions() - Set regions of a target for given address ranges.
239 if (r->ar.start >= range->end) in damon_set_regions()
245 ALIGN_DOWN(range->start, in damon_set_regions()
247 ALIGN(range->end, DAMON_MIN_REGION)); in damon_set_regions()
249 return -ENOMEM; in damon_set_regions()
253 first->ar.start = ALIGN_DOWN(range->start, in damon_set_regions()
255 last->ar.end = ALIGN(range->end, DAMON_MIN_REGION); in damon_set_regions()
274 filter->type = type; in damos_new_filter()
275 filter->matching = matching; in damos_new_filter()
276 INIT_LIST_HEAD(&filter->list); in damos_new_filter()
282 list_add_tail(&f->list, &s->filters); in damos_add_filter()
287 list_del(&f->list); in damos_del_filter()
304 quota->total_charged_sz = 0; in damos_quota_init_priv()
305 quota->total_charged_ns = 0; in damos_quota_init_priv()
306 quota->esz = 0; in damos_quota_init_priv()
307 quota->charged_sz = 0; in damos_quota_init_priv()
308 quota->charged_from = 0; in damos_quota_init_priv()
309 quota->charge_target_from = NULL; in damos_quota_init_priv()
310 quota->charge_addr_from = 0; in damos_quota_init_priv()
323 scheme->pattern = *pattern; in damon_new_scheme()
324 scheme->action = action; in damon_new_scheme()
325 INIT_LIST_HEAD(&scheme->filters); in damon_new_scheme()
326 scheme->stat = (struct damos_stat){}; in damon_new_scheme()
327 INIT_LIST_HEAD(&scheme->list); in damon_new_scheme()
329 scheme->quota = *(damos_quota_init_priv(quota)); in damon_new_scheme()
331 scheme->wmarks = *wmarks; in damon_new_scheme()
332 scheme->wmarks.activated = true; in damon_new_scheme()
339 list_add_tail(&s->list, &ctx->schemes); in damon_add_scheme()
344 list_del(&s->list); in damon_del_scheme()
375 t->pid = NULL; in damon_new_target()
376 t->nr_regions = 0; in damon_new_target()
377 INIT_LIST_HEAD(&t->regions_list); in damon_new_target()
378 INIT_LIST_HEAD(&t->list); in damon_new_target()
385 list_add_tail(&t->list, &ctx->adaptive_targets); in damon_add_target()
390 return list_empty(&ctx->adaptive_targets); in damon_targets_empty()
395 list_del(&t->list); in damon_del_target()
415 return t->nr_regions; in damon_nr_regions()
426 ctx->attrs.sample_interval = 5 * 1000; in damon_new_ctx()
427 ctx->attrs.aggr_interval = 100 * 1000; in damon_new_ctx()
428 ctx->attrs.ops_update_interval = 60 * 1000 * 1000; in damon_new_ctx()
430 ktime_get_coarse_ts64(&ctx->last_aggregation); in damon_new_ctx()
431 ctx->last_ops_update = ctx->last_aggregation; in damon_new_ctx()
433 mutex_init(&ctx->kdamond_lock); in damon_new_ctx()
435 ctx->attrs.min_nr_regions = 10; in damon_new_ctx()
436 ctx->attrs.max_nr_regions = 1000; in damon_new_ctx()
438 INIT_LIST_HEAD(&ctx->adaptive_targets); in damon_new_ctx()
439 INIT_LIST_HEAD(&ctx->schemes); in damon_new_ctx()
448 if (ctx->ops.cleanup) { in damon_destroy_targets()
449 ctx->ops.cleanup(ctx); in damon_destroy_targets()
472 return age * old_attrs->aggr_interval / new_attrs->aggr_interval; in damon_age_for_new_attrs()
480 attrs->aggr_interval / attrs->sample_interval; in damon_accesses_bp_to_nr_accesses()
490 attrs->aggr_interval / attrs->sample_interval; in damon_nr_accesses_to_accesses_bp()
507 r->nr_accesses = damon_nr_accesses_for_new_attrs(r->nr_accesses, in damon_update_monitoring_result()
509 r->age = damon_age_for_new_attrs(r->age, old_attrs, new_attrs); in damon_update_monitoring_result()
513 * region->nr_accesses is the number of sampling intervals in the last
514 * aggregation interval that access to the region has found, and region->age is
517 * sampling interval and aggregation interval. This function updates
518 * ->nr_accesses and ->age of given damon_ctx's regions for new damon_attrs.
523 struct damon_attrs *old_attrs = &ctx->attrs; in damon_update_monitoring_results()
527 /* if any interval is zero, simply forgive conversion */ in damon_update_monitoring_results()
528 if (!old_attrs->sample_interval || !old_attrs->aggr_interval || in damon_update_monitoring_results()
529 !new_attrs->sample_interval || in damon_update_monitoring_results()
530 !new_attrs->aggr_interval) in damon_update_monitoring_results()
540 * damon_set_attrs() - Set attributes for the monitoring.
545 * Every time interval is in micro-seconds.
551 if (attrs->min_nr_regions < 3) in damon_set_attrs()
552 return -EINVAL; in damon_set_attrs()
553 if (attrs->min_nr_regions > attrs->max_nr_regions) in damon_set_attrs()
554 return -EINVAL; in damon_set_attrs()
555 if (attrs->sample_interval > attrs->aggr_interval) in damon_set_attrs()
556 return -EINVAL; in damon_set_attrs()
559 ctx->attrs = *attrs; in damon_set_attrs()
564 * damon_set_schemes() - Set data access monitoring based operation schemes.
585 * damon_nr_running_ctxs() - Return number of currently running contexts.
610 if (ctx->attrs.min_nr_regions) in damon_region_sz_limit()
611 sz /= ctx->attrs.min_nr_regions; in damon_region_sz_limit()
621 * __damon_start() - Starts monitoring with given context.
630 int err = -EBUSY; in __damon_start()
632 mutex_lock(&ctx->kdamond_lock); in __damon_start()
633 if (!ctx->kdamond) { in __damon_start()
635 ctx->kdamond = kthread_run(kdamond_fn, ctx, "kdamond.%d", in __damon_start()
637 if (IS_ERR(ctx->kdamond)) { in __damon_start()
638 err = PTR_ERR(ctx->kdamond); in __damon_start()
639 ctx->kdamond = NULL; in __damon_start()
642 mutex_unlock(&ctx->kdamond_lock); in __damon_start()
648 * damon_start() - Starts the monitorings for a given group of contexts.
658 * returns -EBUSY.
671 return -EBUSY; in damon_start()
688 * __damon_stop() - Stops monitoring of a given context.
697 mutex_lock(&ctx->kdamond_lock); in __damon_stop()
698 tsk = ctx->kdamond; in __damon_stop()
701 mutex_unlock(&ctx->kdamond_lock); in __damon_stop()
706 mutex_unlock(&ctx->kdamond_lock); in __damon_stop()
708 return -EPERM; in __damon_stop()
712 * damon_stop() - Stops the monitorings for a given group of contexts.
732 * damon_check_reset_time_interval() - Check if a time interval is elapsed.
733 * @baseline: the time to check whether the interval has elapsed since
734 * @interval: the time interval (microseconds)
736 * See whether the given time interval has passed since the given baseline
739 * Return: true if the time interval has passed, or false otherwise.
742 unsigned long interval) in damon_check_reset_time_interval() argument
747 if ((timespec64_to_ns(&now) - timespec64_to_ns(baseline)) < in damon_check_reset_time_interval()
748 interval * 1000) in damon_check_reset_time_interval()
759 return damon_check_reset_time_interval(&ctx->last_aggregation, in kdamond_aggregate_interval_passed()
760 ctx->attrs.aggr_interval); in kdamond_aggregate_interval_passed()
776 r->last_nr_accesses = r->nr_accesses; in kdamond_reset_aggregated()
777 r->nr_accesses = 0; in kdamond_reset_aggregated()
791 return s->pattern.min_sz_region <= sz && in __damos_valid_target()
792 sz <= s->pattern.max_sz_region && in __damos_valid_target()
793 s->pattern.min_nr_accesses <= r->nr_accesses && in __damos_valid_target()
794 r->nr_accesses <= s->pattern.max_nr_accesses && in __damos_valid_target()
795 s->pattern.min_age_region <= r->age && in __damos_valid_target()
796 r->age <= s->pattern.max_age_region; in __damos_valid_target()
804 if (!ret || !s->quota.esz || !c->ops.get_scheme_score) in damos_valid_target()
807 return c->ops.get_scheme_score(c, t, r, s) >= s->quota.min_score; in damos_valid_target()
811 * damos_skip_charged_region() - Check if the given region or starting part of
836 struct damos_quota *quota = &s->quota; in damos_skip_charged_region()
840 if (quota->charge_target_from) { in damos_skip_charged_region()
841 if (t != quota->charge_target_from) in damos_skip_charged_region()
844 quota->charge_target_from = NULL; in damos_skip_charged_region()
845 quota->charge_addr_from = 0; in damos_skip_charged_region()
848 if (quota->charge_addr_from && in damos_skip_charged_region()
849 r->ar.end <= quota->charge_addr_from) in damos_skip_charged_region()
852 if (quota->charge_addr_from && r->ar.start < in damos_skip_charged_region()
853 quota->charge_addr_from) { in damos_skip_charged_region()
854 sz_to_skip = ALIGN_DOWN(quota->charge_addr_from - in damos_skip_charged_region()
855 r->ar.start, DAMON_MIN_REGION); in damos_skip_charged_region()
865 quota->charge_target_from = NULL; in damos_skip_charged_region()
866 quota->charge_addr_from = 0; in damos_skip_charged_region()
874 s->stat.nr_tried++; in damos_update_stat()
875 s->stat.sz_tried += sz_tried; in damos_update_stat()
877 s->stat.nr_applied++; in damos_update_stat()
878 s->stat.sz_applied += sz_applied; in damos_update_stat()
889 switch (filter->type) { in __damos_filter_out()
896 matched = target_idx == filter->target_idx; in __damos_filter_out()
899 start = ALIGN_DOWN(filter->addr_range.start, DAMON_MIN_REGION); in __damos_filter_out()
900 end = ALIGN_DOWN(filter->addr_range.end, DAMON_MIN_REGION); in __damos_filter_out()
903 if (start <= r->ar.start && r->ar.end <= end) { in __damos_filter_out()
908 if (r->ar.end <= start || end <= r->ar.start) { in __damos_filter_out()
913 if (r->ar.start < start) { in __damos_filter_out()
914 damon_split_region_at(t, r, start - r->ar.start); in __damos_filter_out()
919 damon_split_region_at(t, r, end - r->ar.start); in __damos_filter_out()
926 return matched == filter->matching; in __damos_filter_out()
944 struct damos_quota *quota = &s->quota; in damos_apply_scheme()
950 if (c->ops.apply_scheme) { in damos_apply_scheme()
951 if (quota->esz && quota->charged_sz + sz > quota->esz) { in damos_apply_scheme()
952 sz = ALIGN_DOWN(quota->esz - quota->charged_sz, in damos_apply_scheme()
961 if (c->callback.before_damos_apply) in damos_apply_scheme()
962 err = c->callback.before_damos_apply(c, t, r, s); in damos_apply_scheme()
964 sz_applied = c->ops.apply_scheme(c, t, r, s); in damos_apply_scheme()
966 quota->total_charged_ns += timespec64_to_ns(&end) - in damos_apply_scheme()
968 quota->charged_sz += sz; in damos_apply_scheme()
969 if (quota->esz && quota->charged_sz >= quota->esz) { in damos_apply_scheme()
970 quota->charge_target_from = t; in damos_apply_scheme()
971 quota->charge_addr_from = r->ar.end + 1; in damos_apply_scheme()
974 if (s->action != DAMOS_STAT) in damos_apply_scheme()
975 r->age = 0; in damos_apply_scheme()
988 struct damos_quota *quota = &s->quota; in damon_do_apply_schemes()
990 if (!s->wmarks.activated) in damon_do_apply_schemes()
994 if (quota->esz && quota->charged_sz >= quota->esz) in damon_do_apply_schemes()
1007 /* Shouldn't be called if quota->ms and quota->sz are zero */
1013 if (!quota->ms) { in damos_set_effective_quota()
1014 quota->esz = quota->sz; in damos_set_effective_quota()
1018 if (quota->total_charged_ns) in damos_set_effective_quota()
1019 throughput = quota->total_charged_sz * 1000000 / in damos_set_effective_quota()
1020 quota->total_charged_ns; in damos_set_effective_quota()
1023 esz = throughput * quota->ms; in damos_set_effective_quota()
1025 if (quota->sz && quota->sz < esz) in damos_set_effective_quota()
1026 esz = quota->sz; in damos_set_effective_quota()
1027 quota->esz = esz; in damos_set_effective_quota()
1032 struct damos_quota *quota = &s->quota; in damos_adjust_quota()
1038 if (!quota->ms && !quota->sz) in damos_adjust_quota()
1042 if (time_after_eq(jiffies, quota->charged_from + in damos_adjust_quota()
1043 msecs_to_jiffies(quota->reset_interval))) { in damos_adjust_quota()
1044 if (quota->esz && quota->charged_sz >= quota->esz) in damos_adjust_quota()
1045 s->stat.qt_exceeds++; in damos_adjust_quota()
1046 quota->total_charged_sz += quota->charged_sz; in damos_adjust_quota()
1047 quota->charged_from = jiffies; in damos_adjust_quota()
1048 quota->charged_sz = 0; in damos_adjust_quota()
1052 if (!c->ops.get_scheme_score) in damos_adjust_quota()
1056 memset(quota->histogram, 0, sizeof(quota->histogram)); in damos_adjust_quota()
1061 score = c->ops.get_scheme_score(c, t, r, s); in damos_adjust_quota()
1062 quota->histogram[score] += damon_sz_region(r); in damos_adjust_quota()
1069 for (cumulated_sz = 0, score = max_score; ; score--) { in damos_adjust_quota()
1070 cumulated_sz += quota->histogram[score]; in damos_adjust_quota()
1071 if (cumulated_sz >= quota->esz || !score) in damos_adjust_quota()
1074 quota->min_score = score; in damos_adjust_quota()
1084 if (!s->wmarks.activated) in kdamond_apply_schemes()
1104 l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) / in damon_merge_two_regions()
1106 l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r); in damon_merge_two_regions()
1107 l->ar.end = r->ar.end; in damon_merge_two_regions()
1115 * thres '->nr_accesses' diff threshold for the merge
1124 if (abs(r->nr_accesses - r->last_nr_accesses) > thres) in damon_merge_regions_of()
1125 r->age = 0; in damon_merge_regions_of()
1127 r->age++; in damon_merge_regions_of()
1129 if (prev && prev->ar.end == r->ar.start && in damon_merge_regions_of()
1130 abs(prev->nr_accesses - r->nr_accesses) <= thres && in damon_merge_regions_of()
1141 * threshold '->nr_accesses' diff threshold for the merge
1162 * sz_r size of the first sub-region that will be made
1169 new = damon_new_region(r->ar.start + sz_r, r->ar.end); in damon_split_region_at()
1173 r->ar.end = new->ar.start; in damon_split_region_at()
1175 new->age = r->age; in damon_split_region_at()
1176 new->last_nr_accesses = r->last_nr_accesses; in damon_split_region_at()
1191 for (i = 0; i < nr_subs - 1 && in damon_split_regions_of()
1194 * Randomly select size of left sub-region to be at in damon_split_regions_of()
1210 * Split every target region into randomly-sized small regions
1212 * This function splits every target region into random-sized small regions if
1214 * user-specified maximum number of regions. This is for maximizing the
1229 if (nr_regions > ctx->attrs.max_nr_regions / 2) in kdamond_split_regions()
1234 nr_regions < ctx->attrs.max_nr_regions / 3) in kdamond_split_regions()
1244 * Check whether it is time to check and apply the operations-related data
1251 return damon_check_reset_time_interval(&ctx->last_ops_update, in kdamond_need_update_operations()
1252 ctx->attrs.ops_update_interval); in kdamond_need_update_operations()
1270 if (!ctx->ops.target_valid) in kdamond_need_stop()
1274 if (ctx->ops.target_valid(t)) in kdamond_need_stop()
1292 return -EINVAL; in damos_wmark_metric_value()
1297 * watermark check in micro-seconds.
1303 if (scheme->wmarks.metric == DAMOS_WMARK_NONE) in damos_wmark_wait_us()
1306 metric = damos_wmark_metric_value(scheme->wmarks.metric); in damos_wmark_wait_us()
1308 if (metric > scheme->wmarks.high || scheme->wmarks.low > metric) { in damos_wmark_wait_us()
1309 if (scheme->wmarks.activated) in damos_wmark_wait_us()
1311 scheme->action, in damos_wmark_wait_us()
1312 metric > scheme->wmarks.high ? in damos_wmark_wait_us()
1314 scheme->wmarks.activated = false; in damos_wmark_wait_us()
1315 return scheme->wmarks.interval; in damos_wmark_wait_us()
1319 if ((scheme->wmarks.high >= metric && metric >= scheme->wmarks.mid) && in damos_wmark_wait_us()
1320 !scheme->wmarks.activated) in damos_wmark_wait_us()
1321 return scheme->wmarks.interval; in damos_wmark_wait_us()
1323 if (!scheme->wmarks.activated) in damos_wmark_wait_us()
1324 pr_debug("activate a scheme (%d)\n", scheme->action); in damos_wmark_wait_us()
1325 scheme->wmarks.activated = true; in damos_wmark_wait_us()
1331 /* See Documentation/timers/timers-howto.rst for the thresholds */ in kdamond_usleep()
1359 if (ctx->callback.after_wmarks_check && in kdamond_wait_activation()
1360 ctx->callback.after_wmarks_check(ctx)) in kdamond_wait_activation()
1363 return -EBUSY; in kdamond_wait_activation()
1377 pr_debug("kdamond (%d) starts\n", current->pid); in kdamond_fn()
1379 if (ctx->ops.init) in kdamond_fn()
1380 ctx->ops.init(ctx); in kdamond_fn()
1381 if (ctx->callback.before_start && ctx->callback.before_start(ctx)) in kdamond_fn()
1390 if (ctx->ops.prepare_access_checks) in kdamond_fn()
1391 ctx->ops.prepare_access_checks(ctx); in kdamond_fn()
1392 if (ctx->callback.after_sampling && in kdamond_fn()
1393 ctx->callback.after_sampling(ctx)) in kdamond_fn()
1396 kdamond_usleep(ctx->attrs.sample_interval); in kdamond_fn()
1398 if (ctx->ops.check_accesses) in kdamond_fn()
1399 max_nr_accesses = ctx->ops.check_accesses(ctx); in kdamond_fn()
1405 if (ctx->callback.after_aggregation && in kdamond_fn()
1406 ctx->callback.after_aggregation(ctx)) in kdamond_fn()
1408 if (!list_empty(&ctx->schemes)) in kdamond_fn()
1412 if (ctx->ops.reset_aggregated) in kdamond_fn()
1413 ctx->ops.reset_aggregated(ctx); in kdamond_fn()
1417 if (ctx->ops.update) in kdamond_fn()
1418 ctx->ops.update(ctx); in kdamond_fn()
1428 if (ctx->callback.before_terminate) in kdamond_fn()
1429 ctx->callback.before_terminate(ctx); in kdamond_fn()
1430 if (ctx->ops.cleanup) in kdamond_fn()
1431 ctx->ops.cleanup(ctx); in kdamond_fn()
1433 pr_debug("kdamond (%d) finishes\n", current->pid); in kdamond_fn()
1434 mutex_lock(&ctx->kdamond_lock); in kdamond_fn()
1435 ctx->kdamond = NULL; in kdamond_fn()
1436 mutex_unlock(&ctx->kdamond_lock); in kdamond_fn()
1439 nr_running_ctxs--; in kdamond_fn()
1448 * struct damon_system_ram_region - System RAM resource address region of
1462 if (a->end - a->start < resource_size(res)) { in walk_system_ram()
1463 a->start = res->start; in walk_system_ram()
1464 a->end = res->end; in walk_system_ram()
1489 * damon_set_region_biggest_system_ram_default() - Set the region of the given
1509 return -EINVAL; in damon_set_region_biggest_system_ram_default()
1513 return -EINVAL; in damon_set_region_biggest_system_ram_default()
1525 return -ENOMEM; in damon_init()
1533 #include "core-test.h"