1
2 #include <xen/lib.h>
3 #include <xen/smp.h>
4 #include <xen/time.h>
5 #include <xen/perfc.h>
6 #include <xen/keyhandler.h>
7 #include <xen/spinlock.h>
8 #include <xen/mm.h>
9 #include <xen/guest_access.h>
10 #include <public/sysctl.h>
11 #include <asm/perfc.h>
12
13 #define PERFCOUNTER( var, name ) { name, TYPE_SINGLE, 0 },
14 #define PERFCOUNTER_ARRAY( var, name, size ) { name, TYPE_ARRAY, size },
15 #define PERFSTATUS( var, name ) { name, TYPE_S_SINGLE, 0 },
16 #define PERFSTATUS_ARRAY( var, name, size ) { name, TYPE_S_ARRAY, size },
17 static const struct {
18 const char *name;
19 enum { TYPE_SINGLE, TYPE_ARRAY,
20 TYPE_S_SINGLE, TYPE_S_ARRAY
21 } type;
22 unsigned int nr_elements;
23 } perfc_info[] = {
24 #include <xen/perfc_defn.h>
25 };
26
27 #define NR_PERFCTRS (sizeof(perfc_info) / sizeof(perfc_info[0]))
28
29 DEFINE_PER_CPU(perfc_t[NUM_PERFCOUNTERS], perfcounters);
30
perfc_printall(unsigned char key)31 void perfc_printall(unsigned char key)
32 {
33 unsigned int i, j;
34 s_time_t now = NOW();
35
36 printk("Xen performance counters SHOW (now = %"PRI_stime")\n", now);
37
38 for ( i = j = 0; i < NR_PERFCTRS; i++ )
39 {
40 unsigned int k, cpu;
41 unsigned long long sum = 0;
42
43 printk("%-32s ", perfc_info[i].name);
44 switch ( perfc_info[i].type )
45 {
46 case TYPE_SINGLE:
47 case TYPE_S_SINGLE:
48 for_each_online_cpu ( cpu )
49 sum += per_cpu(perfcounters, cpu)[j];
50 if ( perfc_info[i].type == TYPE_S_SINGLE )
51 sum = (perfc_t) sum;
52 printk("TOTAL[%12Lu]", sum);
53 if ( sum )
54 {
55 k = 0;
56 for_each_online_cpu ( cpu )
57 {
58 if ( k > 0 && (k % 4) == 0 )
59 printk("\n%53s", "");
60 printk(" CPU%02u[%10"PRIperfc"u]", cpu, per_cpu(perfcounters, cpu)[j]);
61 ++k;
62 }
63 }
64 ++j;
65 break;
66 case TYPE_ARRAY:
67 case TYPE_S_ARRAY:
68 for_each_online_cpu ( cpu )
69 {
70 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
71
72 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
73 sum += counters[k];
74 }
75 if ( perfc_info[i].type == TYPE_S_ARRAY )
76 sum = (perfc_t) sum;
77 printk("TOTAL[%12Lu]", sum);
78 if (sum)
79 {
80 #ifdef CONFIG_PERF_ARRAYS
81 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
82 {
83 sum = 0;
84 for_each_online_cpu ( cpu )
85 sum += per_cpu(perfcounters, cpu)[j + k];
86 if ( perfc_info[i].type == TYPE_S_ARRAY )
87 sum = (perfc_t) sum;
88 if ( (k % 4) == 0 )
89 printk("\n%16s", "");
90 printk(" ARR%02u[%10Lu]", k, sum);
91 }
92 #else
93 k = 0;
94 for_each_online_cpu ( cpu )
95 {
96 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
97 unsigned int n;
98
99 sum = 0;
100 for ( n = 0; n < perfc_info[i].nr_elements; n++ )
101 sum += counters[n];
102 if ( perfc_info[i].type == TYPE_S_ARRAY )
103 sum = (perfc_t) sum;
104 if ( k > 0 && (k % 4) == 0 )
105 printk("\n%53s", "");
106 printk(" CPU%02u[%10Lu]", cpu, sum);
107 ++k;
108 }
109 #endif
110 }
111 j += perfc_info[i].nr_elements;
112 break;
113 }
114 printk("\n");
115 }
116 }
117
perfc_reset(unsigned char key)118 void perfc_reset(unsigned char key)
119 {
120 unsigned int i, j;
121 s_time_t now = NOW();
122
123 if ( key != '\0' )
124 printk("Xen performance counters RESET (now = %"PRI_stime")\n", now);
125
126 /* leave STATUS counters alone -- don't reset */
127
128 for ( i = j = 0; i < NR_PERFCTRS; i++ )
129 {
130 unsigned int cpu;
131
132 switch ( perfc_info[i].type )
133 {
134 case TYPE_SINGLE:
135 for_each_online_cpu ( cpu )
136 per_cpu(perfcounters, cpu)[j] = 0;
137 case TYPE_S_SINGLE:
138 ++j;
139 break;
140 case TYPE_ARRAY:
141 for_each_online_cpu ( cpu )
142 memset(per_cpu(perfcounters, cpu) + j, 0,
143 perfc_info[i].nr_elements * sizeof(perfc_t));
144 case TYPE_S_ARRAY:
145 j += perfc_info[i].nr_elements;
146 break;
147 }
148 }
149
150 arch_perfc_reset();
151 }
152
153 static struct xen_sysctl_perfc_desc perfc_d[NR_PERFCTRS];
154 static xen_sysctl_perfc_val_t *perfc_vals;
155 static unsigned int perfc_nbr_vals;
156 static cpumask_t perfc_cpumap;
157
perfc_copy_info(XEN_GUEST_HANDLE_64 (xen_sysctl_perfc_desc_t)desc,XEN_GUEST_HANDLE_64 (xen_sysctl_perfc_val_t)val)158 static int perfc_copy_info(XEN_GUEST_HANDLE_64(xen_sysctl_perfc_desc_t) desc,
159 XEN_GUEST_HANDLE_64(xen_sysctl_perfc_val_t) val)
160 {
161 unsigned int i, j, v;
162
163 /* We only copy the name and array-size information once. */
164 if ( !cpumask_equal(&cpu_online_map, &perfc_cpumap) )
165 {
166 unsigned int nr_cpus;
167 perfc_cpumap = cpu_online_map;
168 nr_cpus = cpumask_weight(&perfc_cpumap);
169
170 perfc_nbr_vals = 0;
171
172 for ( i = 0; i < NR_PERFCTRS; i++ )
173 {
174 safe_strcpy(perfc_d[i].name, perfc_info[i].name);
175
176 switch ( perfc_info[i].type )
177 {
178 case TYPE_SINGLE:
179 case TYPE_S_SINGLE:
180 perfc_d[i].nr_vals = nr_cpus;
181 break;
182 case TYPE_ARRAY:
183 case TYPE_S_ARRAY:
184 perfc_d[i].nr_vals = perfc_info[i].nr_elements;
185 break;
186 }
187 perfc_nbr_vals += perfc_d[i].nr_vals;
188 }
189
190 xfree(perfc_vals);
191 perfc_vals = xmalloc_array(xen_sysctl_perfc_val_t, perfc_nbr_vals);
192 }
193
194 if ( guest_handle_is_null(desc) )
195 return 0;
196
197 if ( perfc_vals == NULL )
198 return -ENOMEM;
199
200 /* Architecture may fill counters from hardware. */
201 arch_perfc_gather();
202
203 /* We gather the counts together every time. */
204 for ( i = j = v = 0; i < NR_PERFCTRS; i++ )
205 {
206 unsigned int cpu;
207
208 switch ( perfc_info[i].type )
209 {
210 case TYPE_SINGLE:
211 case TYPE_S_SINGLE:
212 for_each_cpu ( cpu, &perfc_cpumap )
213 perfc_vals[v++] = per_cpu(perfcounters, cpu)[j];
214 ++j;
215 break;
216 case TYPE_ARRAY:
217 case TYPE_S_ARRAY:
218 memset(perfc_vals + v, 0, perfc_d[i].nr_vals * sizeof(*perfc_vals));
219 for_each_cpu ( cpu, &perfc_cpumap )
220 {
221 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
222 unsigned int k;
223
224 for ( k = 0; k < perfc_d[i].nr_vals; k++ )
225 perfc_vals[v + k] += counters[k];
226 }
227 v += perfc_d[i].nr_vals;
228 j += perfc_info[i].nr_elements;
229 break;
230 }
231 }
232 BUG_ON(v != perfc_nbr_vals);
233
234 if ( copy_to_guest(desc, perfc_d, NR_PERFCTRS) )
235 return -EFAULT;
236 if ( copy_to_guest(val, perfc_vals, perfc_nbr_vals) )
237 return -EFAULT;
238 return 0;
239 }
240
241 /* Dom0 control of perf counters */
perfc_control(struct xen_sysctl_perfc_op * pc)242 int perfc_control(struct xen_sysctl_perfc_op *pc)
243 {
244 static DEFINE_SPINLOCK(lock);
245 int rc;
246
247 spin_lock(&lock);
248
249 switch ( pc->cmd )
250 {
251 case XEN_SYSCTL_PERFCOP_reset:
252 rc = perfc_copy_info(pc->desc, pc->val);
253 perfc_reset(0);
254 break;
255
256 case XEN_SYSCTL_PERFCOP_query:
257 rc = perfc_copy_info(pc->desc, pc->val);
258 break;
259
260 default:
261 rc = -EINVAL;
262 break;
263 }
264
265 spin_unlock(&lock);
266
267 pc->nr_counters = NR_PERFCTRS;
268 pc->nr_vals = perfc_nbr_vals;
269
270 return rc;
271 }
272
273 /*
274 * Local variables:
275 * mode: C
276 * c-file-style: "BSD"
277 * c-basic-offset: 4
278 * tab-width: 4
279 * indent-tabs-mode: nil
280 * End:
281 */
282