ia64/linux-2.6.18-xen.hg

view arch/mips/oprofile/op_model_mipsxx.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2004, 2005 by Ralf Baechle
7 * Copyright (C) 2005 by MIPS Technologies, Inc.
8 */
9 #include <linux/oprofile.h>
10 #include <linux/interrupt.h>
11 #include <linux/smp.h>
13 #include "op_impl.h"
15 #define M_PERFCTL_EXL (1UL << 0)
16 #define M_PERFCTL_KERNEL (1UL << 1)
17 #define M_PERFCTL_SUPERVISOR (1UL << 2)
18 #define M_PERFCTL_USER (1UL << 3)
19 #define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4)
20 #define M_PERFCTL_EVENT(event) ((event) << 5)
21 #define M_PERFCTL_VPEID(vpe) ((vpe) << 16)
22 #define M_PERFCTL_MT_EN(filter) ((filter) << 20)
23 #define M_TC_EN_ALL M_PERFCTL_MT_EN(0)
24 #define M_TC_EN_VPE M_PERFCTL_MT_EN(1)
25 #define M_TC_EN_TC M_PERFCTL_MT_EN(2)
26 #define M_PERFCTL_TCID(tcid) ((tcid) << 22)
27 #define M_PERFCTL_WIDE (1UL << 30)
28 #define M_PERFCTL_MORE (1UL << 31)
30 #define M_COUNTER_OVERFLOW (1UL << 31)
32 #ifdef CONFIG_MIPS_MT_SMP
33 #define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id()))
34 #else
35 #define WHAT 0
36 #endif
38 #define __define_perf_accessors(r, n, np) \
39 \
40 static inline unsigned int r_c0_ ## r ## n(void) \
41 { \
42 unsigned int cpu = smp_processor_id(); \
43 \
44 switch (cpu) { \
45 case 0: \
46 return read_c0_ ## r ## n(); \
47 case 1: \
48 return read_c0_ ## r ## np(); \
49 default: \
50 BUG(); \
51 } \
52 return 0; \
53 } \
54 \
55 static inline void w_c0_ ## r ## n(unsigned int value) \
56 { \
57 unsigned int cpu = smp_processor_id(); \
58 \
59 switch (cpu) { \
60 case 0: \
61 write_c0_ ## r ## n(value); \
62 return; \
63 case 1: \
64 write_c0_ ## r ## np(value); \
65 return; \
66 default: \
67 BUG(); \
68 } \
69 return; \
70 } \
72 __define_perf_accessors(perfcntr, 0, 2)
73 __define_perf_accessors(perfcntr, 1, 3)
74 __define_perf_accessors(perfcntr, 2, 2)
75 __define_perf_accessors(perfcntr, 3, 2)
77 __define_perf_accessors(perfctrl, 0, 2)
78 __define_perf_accessors(perfctrl, 1, 3)
79 __define_perf_accessors(perfctrl, 2, 2)
80 __define_perf_accessors(perfctrl, 3, 2)
82 struct op_mips_model op_model_mipsxx_ops;
84 static struct mipsxx_register_config {
85 unsigned int control[4];
86 unsigned int counter[4];
87 } reg;
89 /* Compute all of the registers in preparation for enabling profiling. */
91 static void mipsxx_reg_setup(struct op_counter_config *ctr)
92 {
93 unsigned int counters = op_model_mipsxx_ops.num_counters;
94 int i;
96 /* Compute the performance counter control word. */
97 /* For now count kernel and user mode */
98 for (i = 0; i < counters; i++) {
99 reg.control[i] = 0;
100 reg.counter[i] = 0;
102 if (!ctr[i].enabled)
103 continue;
105 reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) |
106 M_PERFCTL_INTERRUPT_ENABLE;
107 if (ctr[i].kernel)
108 reg.control[i] |= M_PERFCTL_KERNEL;
109 if (ctr[i].user)
110 reg.control[i] |= M_PERFCTL_USER;
111 if (ctr[i].exl)
112 reg.control[i] |= M_PERFCTL_EXL;
113 reg.counter[i] = 0x80000000 - ctr[i].count;
114 }
115 }
117 /* Program all of the registers in preparation for enabling profiling. */
119 static void mipsxx_cpu_setup (void *args)
120 {
121 unsigned int counters = op_model_mipsxx_ops.num_counters;
123 switch (counters) {
124 case 4:
125 w_c0_perfctrl3(0);
126 w_c0_perfcntr3(reg.counter[3]);
127 case 3:
128 w_c0_perfctrl2(0);
129 w_c0_perfcntr2(reg.counter[2]);
130 case 2:
131 w_c0_perfctrl1(0);
132 w_c0_perfcntr1(reg.counter[1]);
133 case 1:
134 w_c0_perfctrl0(0);
135 w_c0_perfcntr0(reg.counter[0]);
136 }
137 }
139 /* Start all counters on current CPU */
140 static void mipsxx_cpu_start(void *args)
141 {
142 unsigned int counters = op_model_mipsxx_ops.num_counters;
144 switch (counters) {
145 case 4:
146 w_c0_perfctrl3(WHAT | reg.control[3]);
147 case 3:
148 w_c0_perfctrl2(WHAT | reg.control[2]);
149 case 2:
150 w_c0_perfctrl1(WHAT | reg.control[1]);
151 case 1:
152 w_c0_perfctrl0(WHAT | reg.control[0]);
153 }
154 }
156 /* Stop all counters on current CPU */
157 static void mipsxx_cpu_stop(void *args)
158 {
159 unsigned int counters = op_model_mipsxx_ops.num_counters;
161 switch (counters) {
162 case 4:
163 w_c0_perfctrl3(0);
164 case 3:
165 w_c0_perfctrl2(0);
166 case 2:
167 w_c0_perfctrl1(0);
168 case 1:
169 w_c0_perfctrl0(0);
170 }
171 }
173 static int mipsxx_perfcount_handler(struct pt_regs *regs)
174 {
175 unsigned int counters = op_model_mipsxx_ops.num_counters;
176 unsigned int control;
177 unsigned int counter;
178 int handled = 0;
180 switch (counters) {
181 #define HANDLE_COUNTER(n) \
182 case n + 1: \
183 control = r_c0_perfctrl ## n(); \
184 counter = r_c0_perfcntr ## n(); \
185 if ((control & M_PERFCTL_INTERRUPT_ENABLE) && \
186 (counter & M_COUNTER_OVERFLOW)) { \
187 oprofile_add_sample(regs, n); \
188 w_c0_perfcntr ## n(reg.counter[n]); \
189 handled = 1; \
190 }
191 HANDLE_COUNTER(3)
192 HANDLE_COUNTER(2)
193 HANDLE_COUNTER(1)
194 HANDLE_COUNTER(0)
195 }
197 return handled;
198 }
200 #define M_CONFIG1_PC (1 << 4)
202 static inline int __n_counters(void)
203 {
204 if (!(read_c0_config1() & M_CONFIG1_PC))
205 return 0;
206 if (!(r_c0_perfctrl0() & M_PERFCTL_MORE))
207 return 1;
208 if (!(r_c0_perfctrl1() & M_PERFCTL_MORE))
209 return 2;
210 if (!(r_c0_perfctrl2() & M_PERFCTL_MORE))
211 return 3;
213 return 4;
214 }
216 static inline int n_counters(void)
217 {
218 int counters = __n_counters();
220 #ifndef CONFIG_SMP
221 if (current_cpu_data.cputype == CPU_34K)
222 return counters >> 1;
223 #endif
225 return counters;
226 }
228 static inline void reset_counters(int counters)
229 {
230 switch (counters) {
231 case 4:
232 w_c0_perfctrl3(0);
233 w_c0_perfcntr3(0);
234 case 3:
235 w_c0_perfctrl2(0);
236 w_c0_perfcntr2(0);
237 case 2:
238 w_c0_perfctrl1(0);
239 w_c0_perfcntr1(0);
240 case 1:
241 w_c0_perfctrl0(0);
242 w_c0_perfcntr0(0);
243 }
244 }
246 static int __init mipsxx_init(void)
247 {
248 int counters;
250 counters = n_counters();
251 if (counters == 0) {
252 printk(KERN_ERR "Oprofile: CPU has no performance counters\n");
253 return -ENODEV;
254 }
256 reset_counters(counters);
258 op_model_mipsxx_ops.num_counters = counters;
259 switch (current_cpu_data.cputype) {
260 case CPU_20KC:
261 op_model_mipsxx_ops.cpu_type = "mips/20K";
262 break;
264 case CPU_24K:
265 op_model_mipsxx_ops.cpu_type = "mips/24K";
266 break;
268 case CPU_25KF:
269 op_model_mipsxx_ops.cpu_type = "mips/25K";
270 break;
272 case CPU_34K:
273 op_model_mipsxx_ops.cpu_type = "mips/34K";
274 break;
276 case CPU_74K:
277 op_model_mipsxx_ops.cpu_type = "mips/74K";
278 break;
280 case CPU_5KC:
281 op_model_mipsxx_ops.cpu_type = "mips/5K";
282 break;
284 case CPU_SB1:
285 case CPU_SB1A:
286 op_model_mipsxx_ops.cpu_type = "mips/sb1";
287 break;
289 default:
290 printk(KERN_ERR "Profiling unsupported for this CPU\n");
292 return -ENODEV;
293 }
295 perf_irq = mipsxx_perfcount_handler;
297 return 0;
298 }
300 static void mipsxx_exit(void)
301 {
302 reset_counters(op_model_mipsxx_ops.num_counters);
304 perf_irq = null_perf_irq;
305 }
307 struct op_mips_model op_model_mipsxx_ops = {
308 .reg_setup = mipsxx_reg_setup,
309 .cpu_setup = mipsxx_cpu_setup,
310 .init = mipsxx_init,
311 .exit = mipsxx_exit,
312 .cpu_start = mipsxx_cpu_start,
313 .cpu_stop = mipsxx_cpu_stop,
314 };