1
2 #include <xen/cpumask.h>
3 #include <xen/errno.h>
4 #include <xen/guest_access.h>
5 #include <xen/lib.h>
6 #include <xen/perfc.h>
7 #include <xen/spinlock.h>
8 #include <xen/time.h>
9
10 #include <public/sysctl.h>
11
12 #define PERFCOUNTER( var, name ) { name, TYPE_SINGLE, 0 },
13 #define PERFCOUNTER_ARRAY( var, name, size ) { name, TYPE_ARRAY, size },
14 #define PERFSTATUS( var, name ) { name, TYPE_S_SINGLE, 0 },
15 #define PERFSTATUS_ARRAY( var, name, size ) { name, TYPE_S_ARRAY, size },
16 static const struct {
17 const char *name;
18 enum { TYPE_SINGLE, TYPE_ARRAY,
19 TYPE_S_SINGLE, TYPE_S_ARRAY
20 } type;
21 unsigned int nr_elements;
22 } perfc_info[] = {
23 #include <xen/perfc_defn.h>
24 };
25
26 #define NR_PERFCTRS (sizeof(perfc_info) / sizeof(perfc_info[0]))
27
28 DEFINE_PER_CPU(perfc_t[NUM_PERFCOUNTERS], perfcounters);
29
perfc_printall(unsigned char key)30 void cf_check perfc_printall(unsigned char key)
31 {
32 unsigned int i, j;
33 s_time_t now = NOW();
34
35 printk("Xen performance counters SHOW (now = %"PRI_stime")\n", now);
36
37 for ( i = j = 0; i < NR_PERFCTRS; i++ )
38 {
39 unsigned int k, cpu;
40 unsigned long long sum = 0;
41
42 printk("%-32s ", perfc_info[i].name);
43 switch ( perfc_info[i].type )
44 {
45 case TYPE_SINGLE:
46 case TYPE_S_SINGLE:
47 for_each_online_cpu ( cpu )
48 sum += per_cpu(perfcounters, cpu)[j];
49 if ( perfc_info[i].type == TYPE_S_SINGLE )
50 sum = (perfc_t) sum;
51 printk("TOTAL[%12Lu]", sum);
52 if ( sum )
53 {
54 k = 0;
55 for_each_online_cpu ( cpu )
56 {
57 if ( k > 0 && (k % 4) == 0 )
58 printk("\n%53s", "");
59 printk(" CPU%02u[%10u]", cpu, per_cpu(perfcounters, cpu)[j]);
60 ++k;
61 }
62 }
63 ++j;
64 break;
65 case TYPE_ARRAY:
66 case TYPE_S_ARRAY:
67 for_each_online_cpu ( cpu )
68 {
69 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
70
71 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
72 sum += counters[k];
73 }
74 if ( perfc_info[i].type == TYPE_S_ARRAY )
75 sum = (perfc_t) sum;
76 printk("TOTAL[%12Lu]", sum);
77 if (sum)
78 {
79 #ifdef CONFIG_PERF_ARRAYS
80 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
81 {
82 sum = 0;
83 for_each_online_cpu ( cpu )
84 sum += per_cpu(perfcounters, cpu)[j + k];
85 if ( perfc_info[i].type == TYPE_S_ARRAY )
86 sum = (perfc_t) sum;
87 if ( (k % 4) == 0 )
88 printk("\n%16s", "");
89 printk(" ARR%02u[%10Lu]", k, sum);
90 }
91 #else
92 k = 0;
93 for_each_online_cpu ( cpu )
94 {
95 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
96 unsigned int n;
97
98 sum = 0;
99 for ( n = 0; n < perfc_info[i].nr_elements; n++ )
100 sum += counters[n];
101 if ( perfc_info[i].type == TYPE_S_ARRAY )
102 sum = (perfc_t) sum;
103 if ( k > 0 && (k % 4) == 0 )
104 printk("\n%53s", "");
105 printk(" CPU%02u[%10Lu]", cpu, sum);
106 ++k;
107 }
108 #endif
109 }
110 j += perfc_info[i].nr_elements;
111 break;
112 }
113 printk("\n");
114 }
115 }
116
perfc_reset(unsigned char key)117 void cf_check perfc_reset(unsigned char key)
118 {
119 unsigned int i, j;
120 s_time_t now = NOW();
121
122 if ( key != '\0' )
123 printk("Xen performance counters RESET (now = %"PRI_stime")\n", now);
124
125 /* leave STATUS counters alone -- don't reset */
126
127 for ( i = j = 0; i < NR_PERFCTRS; i++ )
128 {
129 unsigned int cpu;
130
131 switch ( perfc_info[i].type )
132 {
133 case TYPE_SINGLE:
134 for_each_online_cpu ( cpu )
135 per_cpu(perfcounters, cpu)[j] = 0;
136 fallthrough;
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 fallthrough;
145 case TYPE_S_ARRAY:
146 j += perfc_info[i].nr_elements;
147 break;
148 }
149 }
150 }
151
152 #ifdef CONFIG_SYSCTL
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 /* We gather the counts together every time. */
201 for ( i = j = v = 0; i < NR_PERFCTRS; i++ )
202 {
203 unsigned int cpu;
204
205 switch ( perfc_info[i].type )
206 {
207 case TYPE_SINGLE:
208 case TYPE_S_SINGLE:
209 for_each_cpu ( cpu, &perfc_cpumap )
210 perfc_vals[v++] = per_cpu(perfcounters, cpu)[j];
211 ++j;
212 break;
213 case TYPE_ARRAY:
214 case TYPE_S_ARRAY:
215 memset(perfc_vals + v, 0, perfc_d[i].nr_vals * sizeof(*perfc_vals));
216 for_each_cpu ( cpu, &perfc_cpumap )
217 {
218 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
219 unsigned int k;
220
221 for ( k = 0; k < perfc_d[i].nr_vals; k++ )
222 perfc_vals[v + k] += counters[k];
223 }
224 v += perfc_d[i].nr_vals;
225 j += perfc_info[i].nr_elements;
226 break;
227 }
228 }
229 BUG_ON(v != perfc_nbr_vals);
230
231 if ( copy_to_guest(desc, perfc_d, NR_PERFCTRS) )
232 return -EFAULT;
233 if ( copy_to_guest(val, perfc_vals, perfc_nbr_vals) )
234 return -EFAULT;
235 return 0;
236 }
237
238 /* Dom0 control of perf counters */
perfc_control(struct xen_sysctl_perfc_op * pc)239 int perfc_control(struct xen_sysctl_perfc_op *pc)
240 {
241 static DEFINE_SPINLOCK(lock);
242 int rc;
243
244 spin_lock(&lock);
245
246 switch ( pc->cmd )
247 {
248 case XEN_SYSCTL_PERFCOP_reset:
249 rc = perfc_copy_info(pc->desc, pc->val);
250 perfc_reset(0);
251 break;
252
253 case XEN_SYSCTL_PERFCOP_query:
254 rc = perfc_copy_info(pc->desc, pc->val);
255 break;
256
257 default:
258 rc = -EINVAL;
259 break;
260 }
261
262 spin_unlock(&lock);
263
264 pc->nr_counters = NR_PERFCTRS;
265 pc->nr_vals = perfc_nbr_vals;
266
267 return rc;
268 }
269 #endif /* CONFIG_SYSCTL */
270
271 /*
272 * Local variables:
273 * mode: C
274 * c-file-style: "BSD"
275 * c-basic-offset: 4
276 * tab-width: 4
277 * indent-tabs-mode: nil
278 * End:
279 */
280