aboutsummaryrefslogtreecommitdiffstats
path: root/patches/next/mm-damon-implement-DAMON-context-input-only-update-f.patch
blob: 566dd6b251dce40c19c59e97766ed4f13e4fb732 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
From 7295c08cad87459d5607646b7cbc0ba66c170e00 Mon Sep 17 00:00:00 2001
From: SeongJae Park <sj@kernel.org>
Date: Mon, 19 Feb 2024 22:00:35 -0800
Subject: [PATCH] mm/damon: implement DAMON context input-only update function

work in progress.  Only build on test machine confirmed.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 include/linux/damon.h |   5 +
 mm/damon/core.c       | 286 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 291 insertions(+)

diff --git a/include/linux/damon.h b/include/linux/damon.h
index f7da65e1ac04..961b4df672c5 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -714,12 +714,14 @@ 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);
 void damos_add_filter(struct damos *s, struct damos_filter *f);
+void damos_move_filter(struct damos *s, struct damos_filter *f);
 void damos_destroy_filter(struct damos_filter *f);
 
 struct damos_quota_goal *damos_new_quota_goal(
 		enum damos_quota_goal_metric metric,
 		unsigned long target_value);
 void damos_add_quota_goal(struct damos_quota *q, struct damos_quota_goal *g);
+void damos_move_quota_goal(struct damos_quota *q, struct damos_quota_goal *g);
 void damos_destroy_quota_goal(struct damos_quota_goal *goal);
 
 struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
@@ -728,11 +730,13 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
 			struct damos_quota *quota,
 			struct damos_watermarks *wmarks);
 void damon_add_scheme(struct damon_ctx *ctx, struct damos *s);
+void damon_move_scheme(struct damon_ctx *ctx, struct damos *s);
 void damon_destroy_scheme(struct damos *s);
 
 struct damon_target *damon_new_target(void);
 void damon_add_target(struct damon_ctx *ctx, struct damon_target *t);
 bool damon_targets_empty(struct damon_ctx *ctx);
+void damon_move_target(struct damon_ctx *ctx, struct damon_target *t);
 void damon_free_target(struct damon_target *t);
 void damon_destroy_target(struct damon_target *t);
 unsigned int damon_nr_regions(struct damon_target *t);
@@ -742,6 +746,7 @@ void damon_destroy_ctx(struct damon_ctx *ctx);
 int damon_set_attrs(struct damon_ctx *ctx, struct damon_attrs *attrs);
 void damon_set_schemes(struct damon_ctx *ctx,
 			struct damos **schemes, ssize_t nr_schemes);
+int damon_update_ctx(struct damon_ctx *old_ctx, struct damon_ctx *new_ctx);
 int damon_nr_running_ctxs(void);
 bool damon_is_registered_ops(enum damon_ops_id id);
 int damon_register_ops(struct damon_operations *ops);
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 37a19534a6f5..3592e313661f 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -299,6 +299,12 @@ static void damos_del_filter(struct damos_filter *f)
 	list_del(&f->list);
 }
 
+void damos_move_filter(struct damos *s, struct damos_filter *f)
+{
+	damos_del_filter(f);
+	damos_add_filter(s, f);
+}
+
 static void damos_free_filter(struct damos_filter *f)
 {
 	kfree(f);
@@ -335,6 +341,12 @@ static void damos_del_quota_goal(struct damos_quota_goal *g)
 	list_del(&g->list);
 }
 
+void damos_move_quota_goal(struct damos_quota *q, struct damos_quota_goal *g)
+{
+	damos_del_quota_goal(g);
+	damos_add_quota_goal(q, g);
+}
+
 static void damos_free_quota_goal(struct damos_quota_goal *g)
 {
 	kfree(g);
@@ -416,6 +428,12 @@ static void damon_del_scheme(struct damos *s)
 	list_del(&s->list);
 }
 
+void damon_move_scheme(struct damon_ctx *ctx, struct damos *s)
+{
+	damon_del_scheme(s);
+	damon_add_scheme(ctx, s);
+}
+
 static void damon_free_scheme(struct damos *s)
 {
 	kfree(s);
@@ -471,6 +489,12 @@ static void damon_del_target(struct damon_target *t)
 	list_del(&t->list);
 }
 
+void damon_move_target(struct damon_ctx *ctx, struct damon_target *t)
+{
+	damon_del_target(t);
+	damon_add_target(ctx, t);
+}
+
 void damon_free_target(struct damon_target *t)
 {
 	struct damon_region *r, *next;
@@ -692,6 +716,268 @@ void damon_set_schemes(struct damon_ctx *ctx, struct damos **schemes,
 		damon_add_scheme(ctx, schemes[i]);
 }
 
+static struct damos_quota_goal *damos_nth_quota_goal(
+		int n, struct damos_quota *q)
+{
+	struct damos_quota_goal *goal;
+	int i = 0;
+
+	damos_for_each_quota_goal(goal, q) {
+		if (i++ == n)
+			return goal;
+	}
+	return NULL;
+}
+
+
+static void damos_update_quota_goals(struct damos_quota *dst,
+		struct damos_quota *src)
+{
+	struct damos_quota_goal *goal, *next;
+	int i = 0, j = 0;
+
+	damos_for_each_quota_goal_safe(goal, next, dst) {
+		struct damos_quota_goal *src_goal =
+			damos_nth_quota_goal(i++, src);
+
+		if (src_goal) {
+			goal->metric = src_goal->metric;
+			goal->target_value = src_goal->target_value;
+			goal->current_value = src_goal->current_value;
+			goal->last_psi_total = src_goal->last_psi_total;
+			continue;
+		}
+		damos_destroy_quota_goal(goal);
+	}
+	damos_for_each_quota_goal_safe(goal, next, src) {
+		if (j++ < i)
+			continue;
+		damos_move_quota_goal(dst, goal);
+	}
+}
+
+static struct damos_filter *damos_nth_filter(int n, struct damos *s)
+{
+	struct damos_filter *filter;
+	int i = 0;
+
+	damos_for_each_filter(filter, s) {
+		if (i++ == n)
+			return filter;
+	}
+	return NULL;
+}
+
+static int damos_update_filters(struct damos *dst, struct damos *src)
+{
+	struct damos_filter *filter, *next;
+	int i = 0, j = 0;
+
+	damos_for_each_filter_safe(filter, next, dst) {
+		struct damos_filter *src_filter = damos_nth_filter(i++, src);
+
+		if (src_filter) {
+			filter->type = src_filter->type;
+			filter->matching = src_filter->matching;
+			switch (src_filter->type) {
+			case DAMOS_FILTER_TYPE_ANON:
+				break;
+			case DAMOS_FILTER_TYPE_MEMCG:
+				filter->memcg_id = src_filter->memcg_id;
+				break;
+			case DAMOS_FILTER_TYPE_ADDR:
+				filter->addr_range = src_filter->addr_range;
+				break;
+			case DAMOS_FILTER_TYPE_TARGET:
+				filter->target_idx = src_filter->target_idx;
+				break;
+			default:
+				break;
+			}
+			continue;
+		}
+		damos_destroy_filter(filter);
+	}
+
+	damos_for_each_filter_safe(filter, next, src) {
+		if (j++ < i)
+			continue;
+		damos_move_filter(dst, filter);
+	}
+	return 0;
+}
+
+static struct damos *damon_nth_scheme(int n, struct damon_ctx *ctx)
+{
+	struct damos *s;
+	int i = 0;
+
+	damon_for_each_scheme(s, ctx) {
+		if (i++ == n)
+			return s;
+	}
+	return NULL;
+}
+
+static int damon_update_scheme(struct damos *dst, struct damos *src)
+{
+	int err;
+
+	dst->pattern = src->pattern;
+	dst->action = src->action;
+	dst->apply_interval_us = src->apply_interval_us;
+	dst->quota.ms = src->quota.ms;
+	dst->quota.sz = src->quota.sz;
+	dst->quota.reset_interval = src->quota.reset_interval;
+	dst->quota.weight_sz = src->quota.weight_sz;
+	dst->quota.weight_nr_accesses = src->quota.weight_nr_accesses;
+	dst->quota.weight_age = src->quota.weight_age;
+
+	damos_update_quota_goals(&dst->quota, &src->quota);
+
+	dst->wmarks = src->wmarks;
+
+	err = damos_update_filters(dst, src);
+	return err;
+}
+
+static int damon_update_schemes(struct damon_ctx *dst, struct damon_ctx *src)
+{
+	struct damos *scheme, *next;
+	int i = 0, j = 0, err;
+
+	damon_for_each_scheme_safe(scheme, next, dst) {
+		struct damos *src_scheme = damon_nth_scheme(i++, src);
+
+		if (src_scheme) {
+			err = damon_update_scheme(scheme, src_scheme);
+			if (err)
+				return err;
+			continue;
+		}
+		damon_destroy_scheme(scheme);
+	}
+
+	damon_for_each_scheme_safe(scheme, next, src) {
+		if (j++ < i)
+			continue;
+		damon_move_scheme(dst, scheme);
+	}
+	return 0;
+}
+
+static int damon_update_target_regions(struct damon_target *dst,
+		struct damon_target *src)
+{
+	struct damon_addr_range *ranges;
+	int i = 0, err;
+	struct damon_region *r;
+
+	damon_for_each_region(r, src)
+		i++;
+	if (!i)
+		return 0;
+	ranges = kmalloc_array(i, sizeof(*ranges), GFP_KERNEL | __GFP_NOWARN);
+	if (!ranges)
+		return -ENOMEM;
+	i = 0;
+	damon_for_each_region(r, src) {
+		if (r->ar.start > r->ar.end) {
+			err = -EINVAL;
+			goto out;
+		}
+		ranges[i].start = r->ar.start;
+		ranges[i++].end = r->ar.end;
+		if (i == 1)
+			continue;
+		if (ranges[i - 2].end > ranges[i - 1].start) {
+			err = -EINVAL;
+			goto out;
+		}
+	}
+	err = damon_set_regions(dst, ranges, i);
+out:
+	kfree(ranges);
+	return err;
+}
+
+static struct damon_target *damon_nth_target(int n, struct damon_ctx *ctx)
+{
+	struct damon_target *t;
+	int i = 0;
+
+	damon_for_each_target(t, ctx) {
+		if (i++ == n)
+			return t;
+	}
+	return NULL;
+}
+
+static int damon_update_targets(struct damon_ctx *dst, struct damon_ctx *src)
+{
+	struct damon_target *t, *next;
+	int i = 0, j = 0, err;
+
+	damon_for_each_target_safe(t, next, dst) {
+		struct damon_target *src_target = damon_nth_target(i++, src);
+
+		if (damon_target_has_pid(dst))
+			put_pid(t->pid);
+
+		if (src_target) {
+			if (damon_target_has_pid(src))
+				get_pid(src_target->pid);
+			t->pid = src_target->pid;
+
+			err = damon_update_target_regions(t, src_target);
+			if (err)
+				return err;
+			continue;
+		}
+		damon_destroy_target(t);
+	}
+
+	damon_for_each_target_safe(t, next, src) {
+		if (j++ < i)
+			continue;
+		damon_move_target(dst, t);
+	}
+	return 0;
+}
+
+/**
+ * damon_update_ctx_prams() - Update input parameters of given DAMON context.
+ * @old_ctx:	DAMON context that need to be udpated.
+ * @new_ctx:	DAMON context that having new user parameters.
+ *
+ * damon_ctx contains user input parameters for monitoring requests, internal
+ * status of the monitoring, and the results of the monitoring.  This function
+ * updates only input parameters for monitoring requests of @old_ctx with those
+ * of @new_ctx, while keeping the internal status and monitoring results.  This
+ * function is aimed to be used for online tuning-like use case.
+ */
+int damon_update_ctx(struct damon_ctx *old_ctx, struct damon_ctx *new_ctx)
+{
+	int err;
+
+	err = damon_update_schemes(old_ctx, new_ctx);
+	if (err)
+		return err;
+	err = damon_update_targets(old_ctx, new_ctx);
+	if (err)
+		return err;
+	err = damon_set_attrs(old_ctx, &new_ctx->attrs);
+	if (err)
+		return err;
+	/*
+	 * ->ops update should be done at least after targets update, for pid
+	 * handling
+	 */
+	old_ctx->ops = new_ctx->ops;
+
+	return 0;
+}
+
 /**
  * damon_nr_running_ctxs() - Return number of currently running contexts.
  */
-- 
2.39.2