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