1*369c415eSSeongJae Park // SPDX-License-Identifier: GPL-2.0 2*369c415eSSeongJae Park /* 3*369c415eSSeongJae Park * Shows data access monitoring resutls in simple metrics. 4*369c415eSSeongJae Park */ 5*369c415eSSeongJae Park 6*369c415eSSeongJae Park #define pr_fmt(fmt) "damon-stat: " fmt 7*369c415eSSeongJae Park 8*369c415eSSeongJae Park #include <linux/damon.h> 9*369c415eSSeongJae Park #include <linux/init.h> 10*369c415eSSeongJae Park #include <linux/kernel.h> 11*369c415eSSeongJae Park #include <linux/module.h> 12*369c415eSSeongJae Park #include <linux/sort.h> 13*369c415eSSeongJae Park 14*369c415eSSeongJae Park #ifdef MODULE_PARAM_PREFIX 15*369c415eSSeongJae Park #undef MODULE_PARAM_PREFIX 16*369c415eSSeongJae Park #endif 17*369c415eSSeongJae Park #define MODULE_PARAM_PREFIX "damon_stat." 18*369c415eSSeongJae Park 19*369c415eSSeongJae Park static int damon_stat_enabled_store( 20*369c415eSSeongJae Park const char *val, const struct kernel_param *kp); 21*369c415eSSeongJae Park 22*369c415eSSeongJae Park static const struct kernel_param_ops enabled_param_ops = { 23*369c415eSSeongJae Park .set = damon_stat_enabled_store, 24*369c415eSSeongJae Park .get = param_get_bool, 25*369c415eSSeongJae Park }; 26*369c415eSSeongJae Park 27*369c415eSSeongJae Park static bool enabled __read_mostly = IS_ENABLED( 28*369c415eSSeongJae Park CONFIG_DAMON_STAT_ENABLED_DEFAULT); 29*369c415eSSeongJae Park module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); 30*369c415eSSeongJae Park MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT"); 31*369c415eSSeongJae Park 32*369c415eSSeongJae Park static struct damon_ctx *damon_stat_context; 33*369c415eSSeongJae Park 34*369c415eSSeongJae Park static struct damon_ctx *damon_stat_build_ctx(void) 35*369c415eSSeongJae Park { 36*369c415eSSeongJae Park struct damon_ctx *ctx; 37*369c415eSSeongJae Park struct damon_attrs attrs; 38*369c415eSSeongJae Park struct damon_target *target; 39*369c415eSSeongJae Park unsigned long start = 0, end = 0; 40*369c415eSSeongJae Park 41*369c415eSSeongJae Park ctx = damon_new_ctx(); 42*369c415eSSeongJae Park if (!ctx) 43*369c415eSSeongJae Park return NULL; 44*369c415eSSeongJae Park attrs = (struct damon_attrs) { 45*369c415eSSeongJae Park .sample_interval = 5 * USEC_PER_MSEC, 46*369c415eSSeongJae Park .aggr_interval = 100 * USEC_PER_MSEC, 47*369c415eSSeongJae Park .ops_update_interval = 60 * USEC_PER_MSEC * MSEC_PER_SEC, 48*369c415eSSeongJae Park .min_nr_regions = 10, 49*369c415eSSeongJae Park .max_nr_regions = 1000, 50*369c415eSSeongJae Park }; 51*369c415eSSeongJae Park /* 52*369c415eSSeongJae Park * auto-tune sampling and aggregation interval aiming 4% DAMON-observed 53*369c415eSSeongJae Park * accesses ratio, keeping sampling interval in [5ms, 10s] range. 54*369c415eSSeongJae Park */ 55*369c415eSSeongJae Park attrs.intervals_goal = (struct damon_intervals_goal) { 56*369c415eSSeongJae Park .access_bp = 400, .aggrs = 3, 57*369c415eSSeongJae Park .min_sample_us = 5000, .max_sample_us = 10000000, 58*369c415eSSeongJae Park }; 59*369c415eSSeongJae Park if (damon_set_attrs(ctx, &attrs)) 60*369c415eSSeongJae Park goto free_out; 61*369c415eSSeongJae Park 62*369c415eSSeongJae Park /* 63*369c415eSSeongJae Park * auto-tune sampling and aggregation interval aiming 4% DAMON-observed 64*369c415eSSeongJae Park * accesses ratio, keeping sampling interval in [5ms, 10s] range. 65*369c415eSSeongJae Park */ 66*369c415eSSeongJae Park ctx->attrs.intervals_goal = (struct damon_intervals_goal) { 67*369c415eSSeongJae Park .access_bp = 400, .aggrs = 3, 68*369c415eSSeongJae Park .min_sample_us = 5000, .max_sample_us = 10000000, 69*369c415eSSeongJae Park }; 70*369c415eSSeongJae Park if (damon_select_ops(ctx, DAMON_OPS_PADDR)) 71*369c415eSSeongJae Park goto free_out; 72*369c415eSSeongJae Park 73*369c415eSSeongJae Park target = damon_new_target(); 74*369c415eSSeongJae Park if (!target) 75*369c415eSSeongJae Park goto free_out; 76*369c415eSSeongJae Park damon_add_target(ctx, target); 77*369c415eSSeongJae Park if (damon_set_region_biggest_system_ram_default(target, &start, &end)) 78*369c415eSSeongJae Park goto free_out; 79*369c415eSSeongJae Park return ctx; 80*369c415eSSeongJae Park free_out: 81*369c415eSSeongJae Park damon_destroy_ctx(ctx); 82*369c415eSSeongJae Park return NULL; 83*369c415eSSeongJae Park } 84*369c415eSSeongJae Park 85*369c415eSSeongJae Park static int damon_stat_start(void) 86*369c415eSSeongJae Park { 87*369c415eSSeongJae Park damon_stat_context = damon_stat_build_ctx(); 88*369c415eSSeongJae Park if (!damon_stat_context) 89*369c415eSSeongJae Park return -ENOMEM; 90*369c415eSSeongJae Park return damon_start(&damon_stat_context, 1, true); 91*369c415eSSeongJae Park } 92*369c415eSSeongJae Park 93*369c415eSSeongJae Park static void damon_stat_stop(void) 94*369c415eSSeongJae Park { 95*369c415eSSeongJae Park damon_stop(&damon_stat_context, 1); 96*369c415eSSeongJae Park damon_destroy_ctx(damon_stat_context); 97*369c415eSSeongJae Park } 98*369c415eSSeongJae Park 99*369c415eSSeongJae Park static bool damon_stat_init_called; 100*369c415eSSeongJae Park 101*369c415eSSeongJae Park static int damon_stat_enabled_store( 102*369c415eSSeongJae Park const char *val, const struct kernel_param *kp) 103*369c415eSSeongJae Park { 104*369c415eSSeongJae Park bool is_enabled = enabled; 105*369c415eSSeongJae Park int err; 106*369c415eSSeongJae Park 107*369c415eSSeongJae Park err = kstrtobool(val, &enabled); 108*369c415eSSeongJae Park if (err) 109*369c415eSSeongJae Park return err; 110*369c415eSSeongJae Park 111*369c415eSSeongJae Park if (is_enabled == enabled) 112*369c415eSSeongJae Park return 0; 113*369c415eSSeongJae Park 114*369c415eSSeongJae Park if (!damon_stat_init_called) 115*369c415eSSeongJae Park /* 116*369c415eSSeongJae Park * probably called from command line parsing (parse_args()). 117*369c415eSSeongJae Park * Cannot call damon_new_ctx(). Let damon_stat_init() handle. 118*369c415eSSeongJae Park */ 119*369c415eSSeongJae Park return 0; 120*369c415eSSeongJae Park 121*369c415eSSeongJae Park if (enabled) { 122*369c415eSSeongJae Park err = damon_stat_start(); 123*369c415eSSeongJae Park if (err) 124*369c415eSSeongJae Park enabled = false; 125*369c415eSSeongJae Park return err; 126*369c415eSSeongJae Park } 127*369c415eSSeongJae Park damon_stat_stop(); 128*369c415eSSeongJae Park return 0; 129*369c415eSSeongJae Park } 130*369c415eSSeongJae Park 131*369c415eSSeongJae Park static int __init damon_stat_init(void) 132*369c415eSSeongJae Park { 133*369c415eSSeongJae Park int err = 0; 134*369c415eSSeongJae Park 135*369c415eSSeongJae Park damon_stat_init_called = true; 136*369c415eSSeongJae Park 137*369c415eSSeongJae Park /* probably set via command line */ 138*369c415eSSeongJae Park if (enabled) 139*369c415eSSeongJae Park err = damon_stat_start(); 140*369c415eSSeongJae Park 141*369c415eSSeongJae Park if (err && enabled) 142*369c415eSSeongJae Park enabled = false; 143*369c415eSSeongJae Park return err; 144*369c415eSSeongJae Park } 145*369c415eSSeongJae Park 146*369c415eSSeongJae Park module_init(damon_stat_init); 147