xref: /linux/mm/damon/stat.c (revision 369c415e60732b7c8ed33368891581246f580d7a)
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