• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * mm/reclaimacct_show.c
4  *
5  * Copyright (c) 2022 Huawei Technologies Co., Ltd.
6  */
7 
8 #include <linux/fs.h>
9 #include <linux/proc_fs.h>
10 #include <linux/seq_file.h>
11 #include <linux/slab.h>
12 #include <linux/time64.h>
13 #include <linux/sched/clock.h>
14 
15 #include "internal.h"
16 
17 /* Store reclaim accounting data */
18 static struct reclaimacct_show {
19 	u64 delay[NR_DELAY_LV][NR_RA_STUBS];
20 	u64 count[NR_DELAY_LV][NR_RA_STUBS];
21 	u64 max_delay;
22 	u64 max_delay_time;
23 } *ra_show;
24 static DEFINE_SPINLOCK(ra_show_lock);
25 
26 static struct reclaim_efficiency {
27 	u64 time[NR_RA_STUBS];
28 	u64 freed[NR_RA_STUBS];
29 } *ra_eff;
30 static DEFINE_SPINLOCK(ra_eff_lock);
31 
reclaimacct_initialize_show_data(void)32 bool reclaimacct_initialize_show_data(void)
33 {
34 	ra_show = kzalloc(sizeof(struct reclaimacct_show), GFP_KERNEL);
35 	if (!ra_show)
36 		goto fail_show;
37 
38 	ra_eff = kzalloc(sizeof(struct reclaim_efficiency) * RECLAIM_TYPES, GFP_KERNEL);
39 	if (!ra_eff)
40 		goto fail_eff;
41 	return true;
42 
43 fail_eff:
44 	kfree(ra_show);
45 	ra_show = NULL;
46 
47 fail_show:
48 	return false;
49 }
50 
reclaimacct_destroy_show_data(void)51 void reclaimacct_destroy_show_data(void)
52 {
53 	kfree(ra_show);
54 	ra_show = NULL;
55 
56 	kfree(ra_eff);
57 	ra_eff = NULL;
58 }
59 
__reclaimacct_collect_data(int level,struct reclaim_acct * ra)60 static void __reclaimacct_collect_data(int level, struct reclaim_acct *ra)
61 {
62 	int i;
63 
64 	spin_lock(&ra_show_lock);
65 	for (i = 0; i < NR_RA_STUBS; i++) {
66 		ra_show->delay[level][i] += ra->delay[i];
67 		ra_show->count[level][i] += ra->count[i];
68 	}
69 
70 	if (ra->delay[RA_RECLAIM] > ra_show->max_delay) {
71 		ra_show->max_delay = ra->delay[RA_RECLAIM];
72 		ra_show->max_delay_time = sched_clock();
73 	}
74 	spin_unlock(&ra_show_lock);
75 }
76 
reclaimacct_collect_data(void)77 void reclaimacct_collect_data(void)
78 {
79 	int i;
80 	const u64 delay[NR_DELAY_LV] = {
81 		DELAY_LV0, DELAY_LV1, DELAY_LV2, DELAY_LV3, DELAY_LV4, DELAY_LV5
82 	};
83 
84 	if (!ra_show || !current->reclaim_acct)
85 		return;
86 
87 	for (i = 0; i < NR_DELAY_LV; i++) {
88 		if (current->reclaim_acct->delay[RA_RECLAIM] < delay[i]) {
89 			__reclaimacct_collect_data(i, current->reclaim_acct);
90 			break;
91 		}
92 	}
93 }
94 
reclaimacct_proc_show(struct seq_file * m,void * v)95 static int reclaimacct_proc_show(struct seq_file *m, void *v)
96 {
97 	int i, j;
98 	struct reclaimacct_show show;
99 
100 	if (!ra_show)
101 		return 0;
102 
103 	spin_lock(&ra_show_lock);
104 	memcpy(&show, ra_show, sizeof(struct reclaimacct_show));
105 	spin_unlock(&ra_show_lock);
106 
107 	seq_puts(m, "watch_point(unit:ms/-)\t\t0-5ms\t\t5-10ms\t\t");
108 	seq_puts(m, "10-50ms\t\t50-100ms\t100-2000ms\t2000-50000ms\n");
109 	for (i = 0; i < NR_RA_STUBS; i++) {
110 		seq_printf(m, "%s_delay\t\t", stub_name[i]);
111 		for (j = 0; j < NR_DELAY_LV; j++)
112 			seq_printf(m, "%-15llu ", show.delay[j][i] / NSEC_PER_MSEC);
113 		seq_puts(m, "\n");
114 
115 		seq_printf(m, "%s_count\t\t", stub_name[i]);
116 		for (j = 0; j < NR_DELAY_LV; j++)
117 			seq_printf(m, "%-15llu ", show.count[j][i]);
118 		seq_puts(m, "\n");
119 	}
120 	seq_printf(m, "Max delay: %llu\tHappened: %llu\n", show.max_delay, show.max_delay_time);
121 
122 	return 0;
123 }
124 
reclaimacct_proc_open(struct inode * inode,struct file * file)125 static int reclaimacct_proc_open(struct inode *inode, struct file *file)
126 {
127 	return single_open(file, reclaimacct_proc_show, NULL);
128 }
129 
130 static const struct proc_ops reclaimacct_proc_fops = {
131 	.proc_open = reclaimacct_proc_open,
132 	.proc_read = seq_read,
133 	.proc_lseek = seq_lseek,
134 	.proc_release = single_release,
135 };
136 
__reclaimacct_collect_reclaim_efficiency(struct reclaim_acct * ra,enum reclaim_type type)137 static void __reclaimacct_collect_reclaim_efficiency(
138 	struct reclaim_acct *ra, enum reclaim_type type)
139 {
140 	int i;
141 
142 	ra->freed[RA_RECLAIM] = ra->freed[RA_SHRINKFILE] + ra->freed[RA_SHRINKANON];
143 
144 	/* system_reclaim(kswapd/zswapd) is single thread, do not need lock */
145 	if (!is_system_reclaim(type))
146 		spin_lock(&ra_eff_lock);
147 
148 	for (i = 0; i < NR_RA_STUBS; i++) {
149 		ra_eff[type].time[i] += ra->delay[i];
150 		ra_eff[type].freed[i] += ra->freed[i];
151 	}
152 
153 	if (!is_system_reclaim(type))
154 		spin_unlock(&ra_eff_lock);
155 }
156 
reclaimacct_collect_reclaim_efficiency(void)157 void reclaimacct_collect_reclaim_efficiency(void)
158 {
159 	if (!ra_eff || !current->reclaim_acct)
160 		return;
161 
162 	__reclaimacct_collect_reclaim_efficiency(current->reclaim_acct,
163 		current->reclaim_acct->reclaim_type);
164 }
165 
reclaim_efficiency_proc_show(struct seq_file * m,void * v)166 static int reclaim_efficiency_proc_show(struct seq_file *m, void *v)
167 {
168 	int i, j;
169 	struct reclaim_efficiency eff[RECLAIM_TYPES];
170 	const char *stage[NR_RA_STUBS] = {
171 		"total_process",
172 		"drain_pages  ",
173 		"shrink_file  ",
174 		"shrink_anon  ",
175 		"shrink_slab  "
176 	};
177 	const char *type[RECLAIM_TYPES] = {
178 		"direct reclaim",
179 		"kswapd        ",
180 		"zswapd        "
181 	};
182 
183 	if (!ra_eff)
184 		return 0;
185 
186 	spin_lock(&ra_eff_lock);
187 	memcpy(&eff, ra_eff, sizeof(eff));
188 	spin_unlock(&ra_eff_lock);
189 
190 	for (i = 0; i < RECLAIM_TYPES; i++) {
191 		seq_printf(m, "%s time(ms)        freed(page/obj)\n", type[i]);
192 		for (j = 0; j < NR_RA_STUBS; j++)
193 			seq_printf(m, "%s  %-15llu %-15llu\n", stage[j],
194 				eff[i].time[j] / NSEC_PER_MSEC,
195 				eff[i].freed[j]);
196 	}
197 
198 	return 0;
199 }
200 
reclaim_efficiency_proc_open(struct inode * inode,struct file * file)201 static int reclaim_efficiency_proc_open(struct inode *inode, struct file *file)
202 {
203 	return single_open(file, reclaim_efficiency_proc_show, NULL);
204 }
205 
206 static const struct proc_ops reclaim_effi_proc_fops = {
207 	.proc_open = reclaim_efficiency_proc_open,
208 	.proc_read = seq_read,
209 	.proc_lseek = seq_lseek,
210 	.proc_release = single_release,
211 };
212 
proc_reclaimacct_init(void)213 static int __init proc_reclaimacct_init(void)
214 {
215 	proc_create("reclaimacct", 0440, NULL, &reclaimacct_proc_fops);
216 	proc_create("reclaim_efficiency", 0440, NULL, &reclaim_effi_proc_fops);
217 	return 0;
218 }
219 fs_initcall(proc_reclaimacct_init);
220