-
Notifications
You must be signed in to change notification settings - Fork 0
/
page-cache-cgroup-stats-linux-3.10.patch
241 lines (228 loc) · 6.72 KB
/
page-cache-cgroup-stats-linux-3.10.patch
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
diff --git a/block/blk-core.c b/block/blk-core.c
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1876,6 +1876,9 @@ void submit_bio(int rw, struct bio *bio)
count_vm_events(PGPGOUT, count);
} else {
task_io_account_read(bio->bi_size);
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+ mem_cgroup_charge_pagecache_stat(MEM_CGROUP_SUBMIT_IO_READ, bio->bi_size);
+#endif
count_vm_events(PGPGIN, count);
}
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -35,6 +35,15 @@ enum mem_cgroup_page_stat_item {
MEMCG_NR_FILE_MAPPED, /* # of pages charged as file rss */
};
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+enum mem_cgroup_pagecache_stat_index{
+ MEM_CGROUP_PAGECACHE_READ,
+ MEM_CGROUP_READAHEAD_READ,
+ MEM_CGROUP_SUBMIT_IO_READ,
+ MEM_CGROUP_PAGECACHE_STAT_NSTATS,
+};
+#endif
+
struct mem_cgroup_reclaim_cookie {
struct zone *zone;
int priority;
@@ -53,6 +62,11 @@ struct mem_cgroup_reclaim_cookie {
* (Of course, if memcg does memory allocation in future, GFP_KERNEL is sane.)
*/
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+void mem_cgroup_charge_pagecache_stat(enum mem_cgroup_pagecache_stat_index idx,
+ ssize_t written);
+#endif
+
extern int mem_cgroup_newpage_charge(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask);
/* for swap handling */
diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -967,6 +967,12 @@ config CGROUP_HUGETLB
control group is tracked in the third page lru pointer. This means
that we cannot use the controller with huge page less than 3 pages.
+config MEMCG_PAGECACHE_HIT
+ bool "PageCache Hit/Miss stats"
+ depends on MEMCG
+ help
+ Provides statistic
+
config CGROUP_PERF
bool "Enable perf_event per-cpu per-container group (cgroup) monitoring"
depends on PERF_EVENTS && CGROUPS
diff --git a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1515,6 +1515,9 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
break;
}
out:
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+ mem_cgroup_charge_pagecache_stat(MEM_CGROUP_PAGECACHE_READ, retval);
+#endif
return retval;
}
EXPORT_SYMBOL(generic_file_aio_read);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -108,6 +108,14 @@ static const char * const mem_cgroup_stat_names[] = {
"swap",
};
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+static const char * const mem_cgroup_pagecache_stat_names[] = {
+ "general_read",
+ "readahead_read",
+ "submit_bio_read",
+};
+#endif
+
enum mem_cgroup_events_index {
MEM_CGROUP_EVENTS_PGPGIN, /* # of pages paged in */
MEM_CGROUP_EVENTS_PGPGOUT, /* # of pages paged out */
@@ -154,6 +162,12 @@ struct mem_cgroup_stat_cpu {
unsigned long targets[MEM_CGROUP_NTARGETS];
};
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+struct mem_cgroup_pagecache_stat_cpu {
+ u64 count[MEM_CGROUP_PAGECACHE_STAT_NSTATS];
+};
+#endif
+
struct mem_cgroup_reclaim_iter {
/*
* last scanned hierarchy member. Valid only if last_dead_count
@@ -370,6 +384,10 @@ struct mem_cgroup {
atomic_t numainfo_updating;
#endif
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+ struct mem_cgroup_pagecache_stat_cpu __percpu *pagecache_stat;
+#endif
+
/*
* Per cgroup active and inactive list, similar to the
* per zone LRU lists.
@@ -899,6 +917,23 @@ static long mem_cgroup_read_stat(struct mem_cgroup *memcg,
return val;
}
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+static long mem_cgroup_read_pagecache_stat(struct mem_cgroup *memcg,
+ enum mem_cgroup_pagecache_stat_index idx)
+{
+ long val = 0;
+ int cpu;
+
+ get_online_cpus();
+ for_each_online_cpu(cpu)
+ val += per_cpu(memcg->pagecache_stat->count[idx], cpu);
+
+// TODO drains percpu
+ put_online_cpus();
+ return val;
+}
+#endif
+
static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
bool charge)
{
@@ -1107,6 +1142,23 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
return memcg;
}
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+void mem_cgroup_charge_pagecache_stat(enum mem_cgroup_pagecache_stat_index idx,
+ ssize_t written)
+{
+ struct mem_cgroup *memcg;
+
+ preempt_disable();
+ memcg = try_get_mem_cgroup_from_mm(current->mm);
+ if (unlikely(!memcg))
+ memcg = root_mem_cgroup;
+
+ __this_cpu_add(memcg->pagecache_stat->count[idx], written);
+ preempt_enable();
+}
+EXPORT_SYMBOL(mem_cgroup_charge_pagecache_stat);
+#endif
+
/*
* Returns a next (in a pre-order walk) alive memcg (with elevated css
* ref. count) or NULL if the whole root's subtree has been visited.
@@ -5401,6 +5453,28 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
return 0;
}
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+//static ssize_t mem_cgroup_pagecache_stat_reset(struct kernfs_open_file *of, char *buf,
+// size_t nbytes, loff_t off)
+static int mem_cgroup_pagecache_stat_reset(struct cgroup *cont, unsigned int event)
+{
+ int i;
+ int cpu;
+ struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ spin_lock(&memcg->pcp_counter_lock);
+ for (i = 0; i < MEM_CGROUP_PAGECACHE_STAT_NSTATS; i++) {
+ per_cpu(memcg->pagecache_stat->count[i], cpu) = 0;
+ }
+ spin_unlock(&memcg->pcp_counter_lock);
+ }
+ put_online_cpus();
+ return 0;
+}
+#endif
+
static u64 mem_cgroup_move_charge_read(struct cgroup *cgrp,
struct cftype *cft)
{
@@ -5599,6 +5673,22 @@ static int memcg_stat_show(struct cgroup *cont, struct cftype *cft,
return 0;
}
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+//static int memcg_pagecache_stat_show(struct seq_file *m, void *v)
+static int memcg_pagecache_stat_show(struct cgroup *cont, struct cftype *cft,
+ struct seq_file *m)
+{
+ struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+ unsigned int i;
+
+ for (i = 0; i < MEM_CGROUP_PAGECACHE_STAT_NSTATS; i++) {
+ seq_printf(m, "%s %ld\n", mem_cgroup_pagecache_stat_names[i],
+ mem_cgroup_read_pagecache_stat(memcg, i));
+ }
+ return 0;
+}
+#endif
+
static u64 mem_cgroup_swappiness_read(struct cgroup *cgrp, struct cftype *cft)
{
struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
@@ -6134,6 +6224,13 @@ static struct cftype mem_cgroup_files[] = {
},
#endif
#endif
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+ {
+ .name = "pagecache_stat",
+ .trigger = mem_cgroup_pagecache_stat_reset,
+ .read_seq_string = memcg_pagecache_stat_show,
+ },
+#endif
{ }, /* terminate */
};
@@ -6219,6 +6316,11 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
if (!memcg->stat)
goto out_free;
+#ifdef CONFIG_MEMCG_PAGECACHE_HIT
+ memcg->pagecache_stat = alloc_percpu(struct mem_cgroup_pagecache_stat_cpu);
+ if (!memcg->pagecache_stat)
+ goto out_free;
+#endif
spin_lock_init(&memcg->pcp_counter_lock);
return memcg;